NVME has only 4 lanes

NVME has only 4 lanes

/*
   ../../generated/scripts/importbvi.py
   -I
   APRP
   -P
   APRP
   -c
   userclk
   -r
   sys_rst_n
   -r
   axi_aresetn
   -c
   axi_aclk
   -c
   axi_ctl_aclk
   -r
   axi_ctl_aresetn
   -c
   refclk
   -o
   AxiPcie3RootPort.bsv
   cores/vc709/axi_pcie_rp/axi_pcie_rp_stub.v
*/

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

(* always_ready, always_enabled *)
interface AprpAxi;
    interface Clock     aclk;
    method Reset     aresetn();
    method Reset     ctl_aresetn();
endinterface
(* always_ready, always_enabled *)
interface AprpCfg;
    method Bit#(6)     ltssm_state();
endinterface
(* always_ready, always_enabled *)
interface AprpInterrupt;
    method Bit#(1)     out();
endinterface
(* always_ready, always_enabled *)
interface AprpIntx;
    method Bit#(1)     msi_grant();
    method Action      msi_request(Bit#(1) v);
endinterface
(* always_ready, always_enabled *)
interface AprpM_axi;
    method Bit#(32)     araddr();
    method Bit#(2)     arburst();
    method Bit#(4)     arcache();
    method Bit#(3)     arid();
    method Bit#(8)     arlen();
    method Bit#(1)     arlock();
    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#(3)     awid();
    method Bit#(8)     awlen();
    method Bit#(1)     awlock();
    method Bit#(3)     awprot();
    method Action      awready(Bit#(1) v);
    method Bit#(3)     awsize();
    method Bit#(1)     awvalid();
    method Action      bid(Bit#(3) v);
    method Bit#(1)     bready();
    method Action      bresp(Bit#(2) v);
    method Action      bvalid(Bit#(1) v);
    method Action      rdata(Bit#(128) v);
    method Action      rid(Bit#(3) v);
    method Action      rlast(Bit#(1) v);
    method Bit#(1)     rready();
    method Action      rresp(Bit#(2) v);
    method Action      ruser(Bit#(32) v);
    method Action      rvalid(Bit#(1) v);
    method Bit#(128)     wdata();
    method Bit#(1)     wlast();
    method Action      wready(Bit#(1) v);
    method Bit#(16)     wstrb();
    method Bit#(32)     wuser();
    method Bit#(1)     wvalid();
endinterface
(* always_ready, always_enabled *)
interface AprpMsi;
    method Bit#(1)     enable();
    method Action      vector_num(Bit#(5) v);
    method Bit#(3)     vector_width();
endinterface
(* always_ready, always_enabled *)
interface AprpPci;
    method Action      exp_rxn(Bit#(4) v);
    method Action      exp_rxp(Bit#(4) v);
    method Bit#(4)     exp_txn();
    method Bit#(4)     exp_txp();
endinterface
(* always_ready, always_enabled *)
interface AprpS_axi;
    method Action      araddr(Bit#(32) v);
    method Action      arburst(Bit#(2) v);
    method Action      arid(Bit#(4) v);
    method Action      arlen(Bit#(8) v);
    method Bit#(1)     arready();
    method Action      arregion(Bit#(4) v);
    method Action      arsize(Bit#(3) v);
    method Action      arvalid(Bit#(1) v);
    method Action      awaddr(Bit#(32) v);
    method Action      awburst(Bit#(2) v);
    method Action      awid(Bit#(4) v);
    method Action      awlen(Bit#(8) v);
    method Bit#(1)     awready();
    method Action      awregion(Bit#(4) v);
    method Action      awsize(Bit#(3) v);
    method Action      awvalid(Bit#(1) v);
    method Bit#(4)     bid();
    method Action      bready(Bit#(1) v);
    method Bit#(2)     bresp();
    method Bit#(1)     bvalid();
    method Bit#(128)     rdata();
    method Bit#(4)     rid();
    method Bit#(1)     rlast();
    method Action      rready(Bit#(1) v);
    method Bit#(2)     rresp();
    method Bit#(32)     ruser();
    method Bit#(1)     rvalid();
    method Action      wdata(Bit#(128) v);
    method Action      wlast(Bit#(1) v);
    method Bit#(1)     wready();
    method Action      wstrb(Bit#(16) v);
    method Action      wuser(Bit#(32) v);
    method Action      wvalid(Bit#(1) v);
endinterface
(* always_ready, always_enabled *)
interface AprpS_axi_ctl;
    method Action      araddr(Bit#(28) v);
    method Bit#(1)     arready();
    method Action      arvalid(Bit#(1) v);
    method Action      awaddr(Bit#(28) 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      wstrb(Bit#(4) v);
    method Action      wvalid(Bit#(1) v);
endinterface
(* always_ready, always_enabled *)
(* always_ready, always_enabled *)
interface AprpUser;
    method Bit#(1)     link_up();
endinterface
(* always_ready, always_enabled *)
interface APRP;
    interface AprpAxi     axi;
    interface AprpCfg     cfg;
    interface AprpInterrupt     interrupt;
    interface AprpIntx     intx;
    interface AprpM_axi     m_axi;
    interface AprpMsi     msi;
    interface AprpPci     pci;
    interface AprpS_axi     s_axi;
    interface AprpS_axi_ctl     s_axi_ctl;
    interface AprpUser     user;
endinterface
import "BVI" axi_pcie_rp =
module mkAPRP#(Clock axi_aclk_in, Reset axi_aresetn_in, Clock refclk, Reset sys_rst_n)(APRP);
    default_clock clk();
    default_reset rst();
        input_clock axi_ctl_aclk(axi_ctl_aclk) = axi_aclk_in;
    input_clock refclk(refclk) = refclk;
        input_reset sys_rst_n(sys_rst_n) = sys_rst_n;
   input_clock axi_aclk_in() = axi_aclk_in;
   input_reset axi_aresetn_in() clocked_by (axi_aclk_in) = axi_aresetn_in;
    interface AprpAxi     axi;
        output_clock aclk(axi_aclk);
        output_reset aresetn(axi_aresetn) clocked_by (axi_aclk_in);
        output_reset ctl_aresetn(axi_ctl_aresetn) clocked_by (axi_aclk_in);
    endinterface
    interface AprpCfg     cfg;
        method cfg_ltssm_state ltssm_state();
    endinterface
    interface AprpInterrupt     interrupt;
        method interrupt_out out();
    endinterface
    interface AprpIntx     intx;
        method intx_msi_grant msi_grant();
        method msi_request(intx_msi_request) enable((*inhigh*) EN_intx_msi_request);
    endinterface
    interface AprpM_axi     m_axi;
        method m_axi_araddr araddr();
        method m_axi_arburst arburst();
        method m_axi_arcache arcache();
        method m_axi_arid arid();
        method m_axi_arlen arlen();
        method m_axi_arlock arlock();
        method m_axi_arprot arprot();
        method arready(m_axi_arready) enable((*inhigh*) EN_m_axi_arready);
        method m_axi_arsize arsize();
        method m_axi_arvalid arvalid();
        method m_axi_awaddr awaddr();
        method m_axi_awburst awburst();
        method m_axi_awcache awcache();
        method m_axi_awid awid();
        method m_axi_awlen awlen();
        method m_axi_awlock awlock();
        method m_axi_awprot awprot();
        method awready(m_axi_awready) enable((*inhigh*) EN_m_axi_awready);
        method m_axi_awsize awsize();
        method m_axi_awvalid awvalid();
        method bid(m_axi_bid) enable((*inhigh*) EN_m_axi_bid);
        method m_axi_bready bready();
        method bresp(m_axi_bresp) enable((*inhigh*) EN_m_axi_bresp);
        method bvalid(m_axi_bvalid) enable((*inhigh*) EN_m_axi_bvalid);
        method rdata(m_axi_rdata) enable((*inhigh*) EN_m_axi_rdata);
        method rid(m_axi_rid) enable((*inhigh*) EN_m_axi_rid);
        method rlast(m_axi_rlast) enable((*inhigh*) EN_m_axi_rlast);
        method m_axi_rready rready();
        method rresp(m_axi_rresp) enable((*inhigh*) EN_m_axi_rresp);
        method ruser(m_axi_ruser) enable((*inhigh*) EN_m_axi_ruser);
        method rvalid(m_axi_rvalid) enable((*inhigh*) EN_m_axi_rvalid);
        method m_axi_wdata wdata();
        method m_axi_wlast wlast();
        method wready(m_axi_wready) enable((*inhigh*) EN_m_axi_wready);
        method m_axi_wstrb wstrb();
        method m_axi_wuser wuser();
        method m_axi_wvalid wvalid();
    endinterface
    interface AprpMsi     msi;
        method msi_enable enable();
        method vector_num(msi_vector_num) enable((*inhigh*) EN_msi_vector_num);
        method msi_vector_width vector_width();
    endinterface
    interface AprpPci     pci;
        method exp_rxn(pci_exp_rxn) enable((*inhigh*) EN_pci_exp_rxn);
        method exp_rxp(pci_exp_rxp) enable((*inhigh*) EN_pci_exp_rxp);
        method pci_exp_txn exp_txn();
        method pci_exp_txp exp_txp();
    endinterface
    interface AprpS_axi     s_axi;
        method araddr(s_axi_araddr) enable((*inhigh*) EN_s_axi_araddr) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method arburst(s_axi_arburst) enable((*inhigh*) EN_s_axi_arburst) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method arid(s_axi_arid) enable((*inhigh*) EN_s_axi_arid) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method arlen(s_axi_arlen) enable((*inhigh*) EN_s_axi_arlen) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method s_axi_arready arready() clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method arregion(s_axi_arregion) enable((*inhigh*) EN_s_axi_arregion) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method arsize(s_axi_arsize) enable((*inhigh*) EN_s_axi_arsize) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method arvalid(s_axi_arvalid) enable((*inhigh*) EN_s_axi_arvalid) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method awaddr(s_axi_awaddr) enable((*inhigh*) EN_s_axi_awaddr) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method awburst(s_axi_awburst) enable((*inhigh*) EN_s_axi_awburst) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method awid(s_axi_awid) enable((*inhigh*) EN_s_axi_awid) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method awlen(s_axi_awlen) enable((*inhigh*) EN_s_axi_awlen) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method s_axi_awready awready() clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method awregion(s_axi_awregion) enable((*inhigh*) EN_s_axi_awregion) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method awsize(s_axi_awsize) enable((*inhigh*) EN_s_axi_awsize) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method awvalid(s_axi_awvalid) enable((*inhigh*) EN_s_axi_awvalid) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method s_axi_bid bid() clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method bready(s_axi_bready) enable((*inhigh*) EN_s_axi_bready) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method s_axi_bresp bresp() clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method s_axi_bvalid bvalid() clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method s_axi_rdata rdata() clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method s_axi_rid rid() clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method s_axi_rlast rlast() clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method rready(s_axi_rready) enable((*inhigh*) EN_s_axi_rready) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method s_axi_rresp rresp() clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method s_axi_ruser ruser() clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method s_axi_rvalid rvalid() clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method wdata(s_axi_wdata) enable((*inhigh*) EN_s_axi_wdata) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method wlast(s_axi_wlast) enable((*inhigh*) EN_s_axi_wlast) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method s_axi_wready wready() clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method wstrb(s_axi_wstrb) enable((*inhigh*) EN_s_axi_wstrb) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method wuser(s_axi_wuser) enable((*inhigh*) EN_s_axi_wuser) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method wvalid(s_axi_wvalid) enable((*inhigh*) EN_s_axi_wvalid) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
    endinterface
    interface AprpS_axi_ctl     s_axi_ctl;
        method araddr(s_axi_ctl_araddr) enable((*inhigh*) EN_s_axi_ctl_araddr) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method s_axi_ctl_arready arready() clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method arvalid(s_axi_ctl_arvalid) enable((*inhigh*) EN_s_axi_ctl_arvalid) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method awaddr(s_axi_ctl_awaddr) enable((*inhigh*) EN_s_axi_ctl_awaddr) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method s_axi_ctl_awready awready() clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method awvalid(s_axi_ctl_awvalid) enable((*inhigh*) EN_s_axi_ctl_awvalid) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method bready(s_axi_ctl_bready) enable((*inhigh*) EN_s_axi_ctl_bready) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method s_axi_ctl_bresp bresp() clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method s_axi_ctl_bvalid bvalid() clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method s_axi_ctl_rdata rdata() clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method rready(s_axi_ctl_rready) enable((*inhigh*) EN_s_axi_ctl_rready) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method s_axi_ctl_rresp rresp() clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method s_axi_ctl_rvalid rvalid() clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method wdata(s_axi_ctl_wdata) enable((*inhigh*) EN_s_axi_ctl_wdata) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method s_axi_ctl_wready wready() clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method wstrb(s_axi_ctl_wstrb) enable((*inhigh*) EN_s_axi_ctl_wstrb) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method wvalid(s_axi_ctl_wvalid) enable((*inhigh*) EN_s_axi_ctl_wvalid) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
    endinterface
    interface AprpUser     user;
        method user_link_up link_up();
    endinterface
    schedule (cfg.ltssm_state, interrupt.out, intx.msi_grant, intx.msi_request, m_axi.araddr, m_axi.arburst, m_axi.arcache, m_axi.arid, m_axi.arlen, m_axi.arlock, m_axi.arprot, m_axi.arready, m_axi.arsize, m_axi.arvalid, m_axi.awaddr, m_axi.awburst, m_axi.awcache, m_axi.awid, m_axi.awlen, m_axi.awlock, m_axi.awprot, m_axi.awready, m_axi.awsize, m_axi.awvalid, m_axi.bid, m_axi.bready, m_axi.bresp, m_axi.bvalid, m_axi.rdata, m_axi.rid, m_axi.rlast, m_axi.rready, m_axi.rresp, m_axi.ruser, m_axi.rvalid, m_axi.wdata, m_axi.wlast, m_axi.wready, m_axi.wstrb, m_axi.wuser, m_axi.wvalid, msi.enable, msi.vector_num, msi.vector_width, pci.exp_rxn, pci.exp_rxp, pci.exp_txn, pci.exp_txp, s_axi.araddr, s_axi.arburst, s_axi.arid, s_axi.arlen, s_axi.arready, s_axi.arregion, s_axi.arsize, s_axi.arvalid, s_axi.awaddr, s_axi.awburst, s_axi.awid, s_axi.awlen, s_axi.awready, s_axi.awregion, s_axi.awsize, s_axi.awvalid, s_axi.bid, s_axi.bready, s_axi.bresp, s_axi.bvalid, s_axi.rdata, s_axi.rid, s_axi.rlast, s_axi.rready, s_axi.rresp, s_axi.ruser, s_axi.rvalid, s_axi.wdata, s_axi.wlast, s_axi.wready, s_axi.wstrb, s_axi.wuser, s_axi.wvalid, s_axi_ctl.araddr, s_axi_ctl.arready, s_axi_ctl.arvalid, s_axi_ctl.awaddr, s_axi_ctl.awready, s_axi_ctl.awvalid, s_axi_ctl.bready, s_axi_ctl.bresp, s_axi_ctl.bvalid, s_axi_ctl.rdata, s_axi_ctl.rready, s_axi_ctl.rresp, s_axi_ctl.rvalid, s_axi_ctl.wdata, s_axi_ctl.wready, s_axi_ctl.wstrb, s_axi_ctl.wvalid, user.link_up) CF (cfg.ltssm_state, interrupt.out, intx.msi_grant, intx.msi_request, m_axi.araddr, m_axi.arburst, m_axi.arcache, m_axi.arid, m_axi.arlen, m_axi.arlock, m_axi.arprot, m_axi.arready, m_axi.arsize, m_axi.arvalid, m_axi.awaddr, m_axi.awburst, m_axi.awcache, m_axi.awid, m_axi.awlen, m_axi.awlock, m_axi.awprot, m_axi.awready, m_axi.awsize, m_axi.awvalid, m_axi.bid, m_axi.bready, m_axi.bresp, m_axi.bvalid, m_axi.rdata, m_axi.rid, m_axi.rlast, m_axi.rready, m_axi.rresp, m_axi.ruser, m_axi.rvalid, m_axi.wdata, m_axi.wlast, m_axi.wready, m_axi.wstrb, m_axi.wuser, m_axi.wvalid, msi.enable, msi.vector_num, msi.vector_width, pci.exp_rxn, pci.exp_rxp, pci.exp_txn, pci.exp_txp, s_axi.araddr, s_axi.arburst, s_axi.arid, s_axi.arlen, s_axi.arready, s_axi.arregion, s_axi.arsize, s_axi.arvalid, s_axi.awaddr, s_axi.awburst, s_axi.awid, s_axi.awlen, s_axi.awready, s_axi.awregion, s_axi.awsize, s_axi.awvalid, s_axi.bid, s_axi.bready, s_axi.bresp, s_axi.bvalid, s_axi.rdata, s_axi.rid, s_axi.rlast, s_axi.rready, s_axi.rresp, s_axi.ruser, s_axi.rvalid, s_axi.wdata, s_axi.wlast, s_axi.wready, s_axi.wstrb, s_axi.wuser, s_axi.wvalid, s_axi_ctl.araddr, s_axi_ctl.arready, s_axi_ctl.arvalid, s_axi_ctl.awaddr, s_axi_ctl.awready, s_axi_ctl.awvalid, s_axi_ctl.bready, s_axi_ctl.bresp, s_axi_ctl.bvalid, s_axi_ctl.rdata, s_axi_ctl.rready, s_axi_ctl.rresp, s_axi_ctl.rvalid, s_axi_ctl.wdata, s_axi_ctl.wready, s_axi_ctl.wstrb, s_axi_ctl.wvalid, user.link_up);
endmodule

/*
   ../../generated/scripts/importbvi.py
   -I
   APRP
   -P
   APRP
   -c
   userclk
   -r
   sys_rst_n
   -r
   axi_aresetn
   -c
   axi_aclk
   -c
   axi_ctl_aclk
   -r
   axi_ctl_aresetn
   -c
   refclk
   -o
   AxiPcie3RootPort.bsv
   cores/vc709/axi_pcie_rp/axi_pcie_rp_stub.v
*/

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

(* always_ready, always_enabled *)
interface AprpAxi;
    interface Clock     aclk;
    method Reset     aresetn();
    method Reset     ctl_aresetn();
endinterface
(* always_ready, always_enabled *)
interface AprpCfg;
    method Bit#(6)     ltssm_state();
endinterface
(* always_ready, always_enabled *)
interface AprpInterrupt;
    method Bit#(1)     out();
endinterface
(* always_ready, always_enabled *)
interface AprpIntx;
    method Bit#(1)     msi_grant();
    method Action      msi_request(Bit#(1) v);
endinterface
(* always_ready, always_enabled *)
interface AprpM_axi;
    method Bit#(32)     araddr();
    method Bit#(2)     arburst();
    method Bit#(4)     arcache();
    method Bit#(3)     arid();
    method Bit#(8)     arlen();
    method Bit#(1)     arlock();
    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#(3)     awid();
    method Bit#(8)     awlen();
    method Bit#(1)     awlock();
    method Bit#(3)     awprot();
    method Action      awready(Bit#(1) v);
    method Bit#(3)     awsize();
    method Bit#(1)     awvalid();
    method Action      bid(Bit#(3) v);
    method Bit#(1)     bready();
    method Action      bresp(Bit#(2) v);
    method Action      bvalid(Bit#(1) v);
    method Action      rdata(Bit#(128) v);
    method Action      rid(Bit#(3) v);
    method Action      rlast(Bit#(1) v);
    method Bit#(1)     rready();
    method Action      rresp(Bit#(2) v);
    method Action      ruser(Bit#(32) v);
    method Action      rvalid(Bit#(1) v);
    method Bit#(128)     wdata();
    method Bit#(1)     wlast();
    method Action      wready(Bit#(1) v);
    method Bit#(16)     wstrb();
    method Bit#(32)     wuser();
    method Bit#(1)     wvalid();
endinterface
(* always_ready, always_enabled *)
interface AprpMsi;
    method Bit#(1)     enable();
    method Action      vector_num(Bit#(5) v);
    method Bit#(3)     vector_width();
endinterface
(* always_ready, always_enabled *)
interface AprpPci;
    method Action      exp_rxn(Bit#(8) v);
    method Action      exp_rxp(Bit#(8) v);
    method Bit#(8)     exp_txn();
    method Bit#(8)     exp_txp();
endinterface
(* always_ready, always_enabled *)
interface AprpS_axi;
    method Action      araddr(Bit#(32) v);
    method Action      arburst(Bit#(2) v);
    method Action      arid(Bit#(4) v);
    method Action      arlen(Bit#(8) v);
    method Bit#(1)     arready();
    method Action      arregion(Bit#(4) v);
    method Action      arsize(Bit#(3) v);
    method Action      arvalid(Bit#(1) v);
    method Action      awaddr(Bit#(32) v);
    method Action      awburst(Bit#(2) v);
    method Action      awid(Bit#(4) v);
    method Action      awlen(Bit#(8) v);
    method Bit#(1)     awready();
    method Action      awregion(Bit#(4) v);
    method Action      awsize(Bit#(3) v);
    method Action      awvalid(Bit#(1) v);
    method Bit#(4)     bid();
    method Action      bready(Bit#(1) v);
    method Bit#(2)     bresp();
    method Bit#(1)     bvalid();
    method Bit#(128)     rdata();
    method Bit#(4)     rid();
    method Bit#(1)     rlast();
    method Action      rready(Bit#(1) v);
    method Bit#(2)     rresp();
    method Bit#(32)     ruser();
    method Bit#(1)     rvalid();
    method Action      wdata(Bit#(128) v);
    method Action      wlast(Bit#(1) v);
    method Bit#(1)     wready();
    method Action      wstrb(Bit#(16) v);
    method Action      wuser(Bit#(32) v);
    method Action      wvalid(Bit#(1) v);
endinterface
(* always_ready, always_enabled *)
interface AprpS_axi_ctl;
    method Action      araddr(Bit#(28) v);
    method Bit#(1)     arready();
    method Action      arvalid(Bit#(1) v);
    method Action      awaddr(Bit#(28) 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      wstrb(Bit#(4) v);
    method Action      wvalid(Bit#(1) v);
endinterface
(* always_ready, always_enabled *)
(* always_ready, always_enabled *)
interface AprpUser;
    method Bit#(1)     link_up();
endinterface
(* always_ready, always_enabled *)
interface APRP;
    interface AprpAxi     axi;
    interface AprpCfg     cfg;
    interface AprpInterrupt     interrupt;
    interface AprpIntx     intx;
    interface AprpM_axi     m_axi;
    interface AprpMsi     msi;
    interface AprpPci     pci;
    interface AprpS_axi     s_axi;
    interface AprpS_axi_ctl     s_axi_ctl;
    interface AprpUser     user;
endinterface
import "BVI" axi_pcie_rp =
module mkAPRP#(Clock axi_aclk_in, Reset axi_aresetn_in, Clock refclk, Reset sys_rst_n)(APRP);
    default_clock clk();
    default_reset rst();
        input_clock axi_ctl_aclk(axi_ctl_aclk) = axi_aclk_in;
    input_clock refclk(refclk) = refclk;
        input_reset sys_rst_n(sys_rst_n) = sys_rst_n;
   input_clock axi_aclk_in() = axi_aclk_in;
   input_reset axi_aresetn_in() clocked_by (axi_aclk_in) = axi_aresetn_in;
    interface AprpAxi     axi;
        output_clock aclk(axi_aclk);
        output_reset aresetn(axi_aresetn) clocked_by (axi_aclk_in);
        output_reset ctl_aresetn(axi_ctl_aresetn) clocked_by (axi_aclk_in);
    endinterface
    interface AprpCfg     cfg;
        method cfg_ltssm_state ltssm_state();
    endinterface
    interface AprpInterrupt     interrupt;
        method interrupt_out out();
    endinterface
    interface AprpIntx     intx;
        method intx_msi_grant msi_grant();
        method msi_request(intx_msi_request) enable((*inhigh*) EN_intx_msi_request);
    endinterface
    interface AprpM_axi     m_axi;
        method m_axi_araddr araddr();
        method m_axi_arburst arburst();
        method m_axi_arcache arcache();
        method m_axi_arid arid();
        method m_axi_arlen arlen();
        method m_axi_arlock arlock();
        method m_axi_arprot arprot();
        method arready(m_axi_arready) enable((*inhigh*) EN_m_axi_arready);
        method m_axi_arsize arsize();
        method m_axi_arvalid arvalid();
        method m_axi_awaddr awaddr();
        method m_axi_awburst awburst();
        method m_axi_awcache awcache();
        method m_axi_awid awid();
        method m_axi_awlen awlen();
        method m_axi_awlock awlock();
        method m_axi_awprot awprot();
        method awready(m_axi_awready) enable((*inhigh*) EN_m_axi_awready);
        method m_axi_awsize awsize();
        method m_axi_awvalid awvalid();
        method bid(m_axi_bid) enable((*inhigh*) EN_m_axi_bid);
        method m_axi_bready bready();
        method bresp(m_axi_bresp) enable((*inhigh*) EN_m_axi_bresp);
        method bvalid(m_axi_bvalid) enable((*inhigh*) EN_m_axi_bvalid);
        method rdata(m_axi_rdata) enable((*inhigh*) EN_m_axi_rdata);
        method rid(m_axi_rid) enable((*inhigh*) EN_m_axi_rid);
        method rlast(m_axi_rlast) enable((*inhigh*) EN_m_axi_rlast);
        method m_axi_rready rready();
        method rresp(m_axi_rresp) enable((*inhigh*) EN_m_axi_rresp);
        method ruser(m_axi_ruser) enable((*inhigh*) EN_m_axi_ruser);
        method rvalid(m_axi_rvalid) enable((*inhigh*) EN_m_axi_rvalid);
        method m_axi_wdata wdata();
        method m_axi_wlast wlast();
        method wready(m_axi_wready) enable((*inhigh*) EN_m_axi_wready);
        method m_axi_wstrb wstrb();
        method m_axi_wuser wuser();
        method m_axi_wvalid wvalid();
    endinterface
    interface AprpMsi     msi;
        method msi_enable enable();
        method vector_num(msi_vector_num) enable((*inhigh*) EN_msi_vector_num);
        method msi_vector_width vector_width();
    endinterface
    interface AprpPci     pci;
        method exp_rxn(pci_exp_rxn) enable((*inhigh*) EN_pci_exp_rxn);
        method exp_rxp(pci_exp_rxp) enable((*inhigh*) EN_pci_exp_rxp);
        method pci_exp_txn exp_txn();
        method pci_exp_txp exp_txp();
    endinterface
    interface AprpS_axi     s_axi;
        method araddr(s_axi_araddr) enable((*inhigh*) EN_s_axi_araddr) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method arburst(s_axi_arburst) enable((*inhigh*) EN_s_axi_arburst) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method arid(s_axi_arid) enable((*inhigh*) EN_s_axi_arid) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method arlen(s_axi_arlen) enable((*inhigh*) EN_s_axi_arlen) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method s_axi_arready arready() clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method arregion(s_axi_arregion) enable((*inhigh*) EN_s_axi_arregion) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method arsize(s_axi_arsize) enable((*inhigh*) EN_s_axi_arsize) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method arvalid(s_axi_arvalid) enable((*inhigh*) EN_s_axi_arvalid) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method awaddr(s_axi_awaddr) enable((*inhigh*) EN_s_axi_awaddr) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method awburst(s_axi_awburst) enable((*inhigh*) EN_s_axi_awburst) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method awid(s_axi_awid) enable((*inhigh*) EN_s_axi_awid) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method awlen(s_axi_awlen) enable((*inhigh*) EN_s_axi_awlen) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method s_axi_awready awready() clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method awregion(s_axi_awregion) enable((*inhigh*) EN_s_axi_awregion) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method awsize(s_axi_awsize) enable((*inhigh*) EN_s_axi_awsize) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method awvalid(s_axi_awvalid) enable((*inhigh*) EN_s_axi_awvalid) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method s_axi_bid bid() clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method bready(s_axi_bready) enable((*inhigh*) EN_s_axi_bready) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method s_axi_bresp bresp() clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method s_axi_bvalid bvalid() clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method s_axi_rdata rdata() clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method s_axi_rid rid() clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method s_axi_rlast rlast() clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method rready(s_axi_rready) enable((*inhigh*) EN_s_axi_rready) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method s_axi_rresp rresp() clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method s_axi_ruser ruser() clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method s_axi_rvalid rvalid() clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method wdata(s_axi_wdata) enable((*inhigh*) EN_s_axi_wdata) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method wlast(s_axi_wlast) enable((*inhigh*) EN_s_axi_wlast) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method s_axi_wready wready() clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method wstrb(s_axi_wstrb) enable((*inhigh*) EN_s_axi_wstrb) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method wuser(s_axi_wuser) enable((*inhigh*) EN_s_axi_wuser) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method wvalid(s_axi_wvalid) enable((*inhigh*) EN_s_axi_wvalid) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
    endinterface
    interface AprpS_axi_ctl     s_axi_ctl;
        method araddr(s_axi_ctl_araddr) enable((*inhigh*) EN_s_axi_ctl_araddr) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method s_axi_ctl_arready arready() clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method arvalid(s_axi_ctl_arvalid) enable((*inhigh*) EN_s_axi_ctl_arvalid) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method awaddr(s_axi_ctl_awaddr) enable((*inhigh*) EN_s_axi_ctl_awaddr) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method s_axi_ctl_awready awready() clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method awvalid(s_axi_ctl_awvalid) enable((*inhigh*) EN_s_axi_ctl_awvalid) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method bready(s_axi_ctl_bready) enable((*inhigh*) EN_s_axi_ctl_bready) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method s_axi_ctl_bresp bresp() clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method s_axi_ctl_bvalid bvalid() clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method s_axi_ctl_rdata rdata() clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method rready(s_axi_ctl_rready) enable((*inhigh*) EN_s_axi_ctl_rready) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method s_axi_ctl_rresp rresp() clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method s_axi_ctl_rvalid rvalid() clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method wdata(s_axi_ctl_wdata) enable((*inhigh*) EN_s_axi_ctl_wdata) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method s_axi_ctl_wready wready() clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method wstrb(s_axi_ctl_wstrb) enable((*inhigh*) EN_s_axi_ctl_wstrb) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
        method wvalid(s_axi_ctl_wvalid) enable((*inhigh*) EN_s_axi_ctl_wvalid) clocked_by (axi_aclk_in) reset_by (axi_aresetn_in);
    endinterface
    interface AprpUser     user;
        method user_link_up link_up();
    endinterface
    schedule (cfg.ltssm_state, interrupt.out, intx.msi_grant, intx.msi_request, m_axi.araddr, m_axi.arburst, m_axi.arcache, m_axi.arid, m_axi.arlen, m_axi.arlock, m_axi.arprot, m_axi.arready, m_axi.arsize, m_axi.arvalid, m_axi.awaddr, m_axi.awburst, m_axi.awcache, m_axi.awid, m_axi.awlen, m_axi.awlock, m_axi.awprot, m_axi.awready, m_axi.awsize, m_axi.awvalid, m_axi.bid, m_axi.bready, m_axi.bresp, m_axi.bvalid, m_axi.rdata, m_axi.rid, m_axi.rlast, m_axi.rready, m_axi.rresp, m_axi.ruser, m_axi.rvalid, m_axi.wdata, m_axi.wlast, m_axi.wready, m_axi.wstrb, m_axi.wuser, m_axi.wvalid, msi.enable, msi.vector_num, msi.vector_width, pci.exp_rxn, pci.exp_rxp, pci.exp_txn, pci.exp_txp, s_axi.araddr, s_axi.arburst, s_axi.arid, s_axi.arlen, s_axi.arready, s_axi.arregion, s_axi.arsize, s_axi.arvalid, s_axi.awaddr, s_axi.awburst, s_axi.awid, s_axi.awlen, s_axi.awready, s_axi.awregion, s_axi.awsize, s_axi.awvalid, s_axi.bid, s_axi.bready, s_axi.bresp, s_axi.bvalid, s_axi.rdata, s_axi.rid, s_axi.rlast, s_axi.rready, s_axi.rresp, s_axi.ruser, s_axi.rvalid, s_axi.wdata, s_axi.wlast, s_axi.wready, s_axi.wstrb, s_axi.wuser, s_axi.wvalid, s_axi_ctl.araddr, s_axi_ctl.arready, s_axi_ctl.arvalid, s_axi_ctl.awaddr, s_axi_ctl.awready, s_axi_ctl.awvalid, s_axi_ctl.bready, s_axi_ctl.bresp, s_axi_ctl.bvalid, s_axi_ctl.rdata, s_axi_ctl.rready, s_axi_ctl.rresp, s_axi_ctl.rvalid, s_axi_ctl.wdata, s_axi_ctl.wready, s_axi_ctl.wstrb, s_axi_ctl.wvalid, user.link_up) CF (cfg.ltssm_state, interrupt.out, intx.msi_grant, intx.msi_request, m_axi.araddr, m_axi.arburst, m_axi.arcache, m_axi.arid, m_axi.arlen, m_axi.arlock, m_axi.arprot, m_axi.arready, m_axi.arsize, m_axi.arvalid, m_axi.awaddr, m_axi.awburst, m_axi.awcache, m_axi.awid, m_axi.awlen, m_axi.awlock, m_axi.awprot, m_axi.awready, m_axi.awsize, m_axi.awvalid, m_axi.bid, m_axi.bready, m_axi.bresp, m_axi.bvalid, m_axi.rdata, m_axi.rid, m_axi.rlast, m_axi.rready, m_axi.rresp, m_axi.ruser, m_axi.rvalid, m_axi.wdata, m_axi.wlast, m_axi.wready, m_axi.wstrb, m_axi.wuser, m_axi.wvalid, msi.enable, msi.vector_num, msi.vector_width, pci.exp_rxn, pci.exp_rxp, pci.exp_txn, pci.exp_txp, s_axi.araddr, s_axi.arburst, s_axi.arid, s_axi.arlen, s_axi.arready, s_axi.arregion, s_axi.arsize, s_axi.arvalid, s_axi.awaddr, s_axi.awburst, s_axi.awid, s_axi.awlen, s_axi.awready, s_axi.awregion, s_axi.awsize, s_axi.awvalid, s_axi.bid, s_axi.bready, s_axi.bresp, s_axi.bvalid, s_axi.rdata, s_axi.rid, s_axi.rlast, s_axi.rready, s_axi.rresp, s_axi.ruser, s_axi.rvalid, s_axi.wdata, s_axi.wlast, s_axi.wready, s_axi.wstrb, s_axi.wuser, s_axi.wvalid, s_axi_ctl.araddr, s_axi_ctl.arready, s_axi_ctl.arvalid, s_axi_ctl.awaddr, s_axi_ctl.awready, s_axi_ctl.awvalid, s_axi_ctl.bready, s_axi_ctl.bresp, s_axi_ctl.bvalid, s_axi_ctl.rdata, s_axi_ctl.rready, s_axi_ctl.rresp, s_axi_ctl.rvalid, s_axi_ctl.wdata, s_axi_ctl.wready, s_axi_ctl.wstrb, s_axi_ctl.wvalid, user.link_up);
endmodule


updated copyright

updated copyright

// Copyright (c) 2014-2015 Quanta Research Cambridge, Inc.
// Copyright (c) 2015 Connectal Project

// 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 Pcie3EndpointX7;

import BRAMFIFO          ::*;
import Clocks            ::*;
import Vector            ::*;
import BuildVector       ::*;
import Connectable       ::*;
import GetPut            ::*;
import Reserved          ::*;
import TieOff            ::*;
import DefaultValue      ::*;
import DReg              ::*;
import Gearbox           ::*;
import FIFO              ::*;
import FIFOF             ::*;
import CFFIFO            ::*;
import SpecialFIFOs      ::*;
import ClientServer      ::*;
import Real              ::*;
import XilinxVirtex7PCIE ::*;
import BUtils            ::*;
import Probe             ::*;

import ConnectalConfig::*;
import ConnectalClocks   ::*;
import ConnectalXilinxCells   ::*;
import XilinxCells       ::*;
import PCIE              ::*;
import PCIEWRAPPER3      ::*;
import Bufgctrl           ::*;
import PcieGearbox       :: *;
import Pipe              :: *;

interface PcieEndpointX7#(numeric type lanes);
   interface PciewrapPci_exp#(lanes)           pcie;
   interface PciewrapUser#(lanes)              user;
   interface PciewrapPipe#(lanes)              pipe;
   interface PciewrapCommon#(lanes)            common;
   interface Server#(TLPData#(16), TLPData#(16)) tlpr;
   interface Server#(TLPData#(16), TLPData#(16)) tlpc;
   interface Put#(Tuple2#(Bit#(64),Bit#(32)))  interruptRequest;
   interface PipeOut#(Bit#(64)) regChanges;
   interface Clock epPcieClock;
   interface Reset epPcieReset;
   interface Clock epPortalClock;
   interface Reset epPortalReset;
   interface Clock epDerivedClock;
   interface Reset epDerivedReset;
endinterface

typedef struct {
   Bit #(256)     data;
   Bool          sop;
   Bool          eop;
   Bit #(8)      keep;
   TLPFirstDWBE  first_be;
   TLPFirstDWBE  last_be;
} AxiStCq deriving (Bits, Eq);

typedef struct {
   Bit #(256)     data;
   Bit #(8)      keep;
   Bool          last;
} AxiStCc deriving (Bits, Eq);

typedef struct {
   Bit #(256)     data;
   Bool          last;
   Bit #(8)      keep;
   Bit #(4)      first_be;
   Bit #(4)      last_be;
} AxiStRq deriving (Bits, Eq);

typedef struct {
   Bit #(256)     data;
   Bool          sop;
   Bool          eop;
   Bit #(8)      keep;
   Bit #(8)      be;
} AxiStRc deriving (Bits, Eq);

function TLPData#(16) convertCQDescriptorToTLP16(CQDescriptor desc, Bit#(32) data, TLPFirstDWBE first, TLPLastDWBE last);
   TLPMemoryIO3DWHeader header = defaultValue;
   header.format     = tpl_1(convertCQReqTypeToTLPFmtType(desc.reqtype));
   header.pkttype    = tpl_2(convertCQReqTypeToTLPFmtType(desc.reqtype));
   header.tclass     = desc.tclass;
   header.relaxed    = desc.relaxed;
   header.nosnoop    = desc.nosnoop;
   header.length     = (desc.dwcount == 1024) ? 0 : truncate(desc.dwcount);
   header.reqid      = desc.reqid;
   header.tag        = desc.tag;
   header.lastbe     = last;
   header.firstbe    = first;
   header.addr       = truncate(desc.address);
   header.data       = convertDW(data);

   Bool is3DW = isReadReqType(desc.reqtype);
   Bool is3Or4DW = isReadReqType(desc.reqtype) || (desc.dwcount == 1);

   TLPData#(16) retval = defaultValue;
   retval.sof   = True;
   retval.eof   = is3Or4DW;
   retval.hit   = (1 << pack(desc.barid));
   retval.data  = pack(header);
   retval.be    = (is3DW ? 16'hFFF0 : 16'hFFFF);

   return retval;
endfunction

function TLPData#(16) convertRCDescriptorToTLP16(RCDescriptor desc, Bit#(32) data);
   TLPCompletionHeader header = defaultValue;
   header.tclass    = desc.tclass;
   header.relaxed   = desc.relaxed;
   header.nosnoop   = desc.nosnoop;
   header.cmplid    = desc.complid;
   header.tag       = desc.tag;
   header.reqid     = desc.reqid;
   header.poison    = desc.poisoned;
   header.cstatus   = desc.status;
   header.length    = (desc.dwcount == 1024) ? 0 : truncate(desc.dwcount);
   header.bytecount = (desc.bytecount == 4096) ? 0 : truncate(desc.bytecount);
   header.loweraddr = truncate(desc.loweraddr);
   header.data      = convertDW(data);

   Bool is3DW = (desc.dwcount == 0);
   Bool is3Or4DW = (desc.dwcount == 0) || (desc.dwcount == 1);
   TLPData#(16) retval = defaultValue;
   retval.sof   = True;
   retval.eof   = is3Or4DW;
   retval.hit   = 1; // XXX
   retval.data  = pack(header);
   retval.be    = (is3DW ? 16'hFFF0 : 16'hFFFF);

   return retval;
endfunction

typedef struct {
   Bit#(32) timestamp;
   Bit#(8) src;
   Bit#(24) value;
} RegChange deriving (Bits);

typedef enum {
   Pcie3Cfg_none,
   Pcie3Cfg_current_speed,
   Pcie3Cfg_dpa_substate_change,
   Pcie3Cfg_err_cor_out,
   Pcie3Cfg_err_fatal_out,
   Pcie3Cfg_err_nonfatal_out,
   Pcie3Cfg_flr_in_process,
   Pcie3Cfg_function_power_state,
   Pcie3Cfg_function_status,
   Pcie3Cfg_hot_reset_out,
   Pcie3Cfg_link_power_state,
   Pcie3Cfg_ltr_enable,
   Pcie3Cfg_ltssm_state,
   Pcie3Cfg_max_payload,
   Pcie3Cfg_max_read_req,
   Pcie3Cfg_negotiated_width,
   Pcie3Cfg_obff_enable,
   Pcie3Cfg_phy_link_down,
   Pcie3Cfg_phy_link_status,
   Pcie3Cfg_pl_status_change,
   Pcie3Cfg_power_state_change_interrupt,
   Pcie3Cfg_rcb_status,
   Pcie3Cfg_rq_backpressure
   } Pcie3CfgType deriving (Bits,Eq);

(* synthesize *)
module mkPcieEndpointX7(PcieEndpointX7#(PcieLanes));

   PCIEParams params = defaultValue;
   Clock defaultClock <- exposeCurrentClock();
   Reset defaultReset <- exposeCurrentReset();
   Reset defaultResetInverted <- mkResetInverter(defaultReset, clocked_by defaultClock);
   PcieWrap#(PcieLanes) pcie_ep <- mkPcieWrap(defaultClock, defaultResetInverted);

   // The PCIe endpoint exports full (250MHz) and half-speed (125MHz) clocks
   Clock pcieClock250 = pcie_ep.user_clk;
   Reset user_reset_n <- mkResetInverter(pcie_ep.user_reset, clocked_by pcie_ep.user_clk);
   Reset pcieReset250 <- mkAsyncReset(4, user_reset_n, pcieClock250);

   ClockGenerator7Params     clkgenParams = defaultValue;
   clkgenParams.clkin1_period    = 4.000; //  250MHz
   clkgenParams.clkin1_period    = 4.000;
   clkgenParams.clkin_buffer     = False;
   clkgenParams.clkfbout_mult_f  = 4.000; // 1000MHz
   clkgenParams.clkout0_divide_f = derivedClockPeriod;
   clkgenParams.clkout1_divide     = round(mainClockPeriod);
   clkgenParams.clkout1_duty_cycle = 0.5;
   clkgenParams.clkout1_phase      = 0.0000;
   ClockGenerator7           clkgen <- mkClockGenerator7(clkgenParams, clocked_by pcieClock250, reset_by pcieReset250);
   Clock mainClock = clkgen.clkout1;
   Reset mainReset <- mkAsyncReset(4, pcieReset250, mainClock);
   Clock derivedClock = clkgen.clkout0;
   Reset derivedReset <- mkAsyncReset(4, pcieReset250, derivedClock);
   Reset user_reset <- mkAsyncReset(2, pcie_ep.user_reset, pcie_ep.user_clk);

   // FIFOS
   FIFOF#(AxiStCq) fAxiCq <- mkFIFOF(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   FIFOF#(AxiStRc) fAxiRc <- mkCFFIFOF(clocked_by pcie_ep.user_clk, reset_by user_reset_n);

   FIFOF#(AxiStRq) fAxiRq <- mkCFFIFOF(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   FIFOF#(AxiStCc) fAxiCc <- mkFIFOF(clocked_by pcie_ep.user_clk, reset_by user_reset_n);

   FIFOF#(TLPData#(16)) fcq <- mkFIFOF(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   FIFOF#(TLPData#(16)) frc <- mkFIFOF(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   FIFOF#(TLPData#(16)) fcc <- mkFIFOF(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   FIFOF#(TLPData#(16)) frq <- mkFIFOF(clocked_by pcie_ep.user_clk, reset_by user_reset_n);

   FIFOF#(Tuple2#(Bit#(64),Bit#(32))) intrFifo <- mkFIFOF(clocked_by pcie_ep.user_clk, reset_by user_reset_n);

   // Drive s_axis_rq
   let rq_txready = (pcie_ep.s_axis_rq.tready != 0 && fAxiRq.notEmpty);

   //(* fire_when_enabled, no_implicit_conditions *)
   rule drive_axi_rq if (rq_txready);
      let info = fAxiRq.first; fAxiRq.deq;
      pcie_ep.s_axis_rq.tvalid(1);
      pcie_ep.s_axis_rq.tlast(pack(info.last));
      pcie_ep.s_axis_rq.tdata(info.data);
      pcie_ep.s_axis_rq.tkeep(info.keep);
      pcie_ep.s_axis_rq.tuser({0, info.last_be, info.first_be});
   endrule

   (* fire_when_enabled, no_implicit_conditions *)
   rule drive_axi_rq2 if (!rq_txready);
      pcie_ep.s_axis_rq.tvalid(0);
      pcie_ep.s_axis_rq.tlast(0);
      pcie_ep.s_axis_rq.tdata(0);
      pcie_ep.s_axis_rq.tkeep(0);
      pcie_ep.s_axis_rq.tuser(0);
   endrule

   Reg#(Bit#(16)) rqBackpressureCycles <- mkReg(0, clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   Reg#(Bit#(16)) rqBackpressureCount <- mkReg(0, clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   Reg#(Bool)     rqBackpressure       <- mkReg(False, clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   Reg#(Bit#(32)) rqBackpressureCountSum <- mkReg(0, clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   Reg#(Bit#(32)) rqBackpressureEvents   <- mkReg(0, clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_rqBackpressureCycles <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_rqBackpressureCount <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_rqBackpressure       <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   Probe#(Bit#(32)) probe_rqBackpressureCountSum <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   Probe#(Bit#(32)) probe_rqBackpressureEvents   <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_fAxiRqNotEmpty       <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_SAxsiRqTReady        <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   rule rltready;
      probe_fAxiRqNotEmpty <= fAxiRq.notEmpty();
      probe_SAxsiRqTReady <= pcie_ep.s_axis_rq.tready;
   endrule
   rule rlBackpressureEnter if (!rqBackpressure);
      if (pcie_ep.s_axis_rq.tready == 0 && fAxiRq.notEmpty) begin
	 rqBackpressure <= True;
	 rqBackpressureCycles <= 0;
	 probe_rqBackpressure <= True;
	 probe_rqBackpressureCycles <= 0;
      end
   endrule
   rule rlBackpressureExit if (rqBackpressure);
      rqBackpressureCycles <= rqBackpressureCycles + 1;
      probe_rqBackpressureCycles <= rqBackpressureCycles + 1;
      if (pcie_ep.s_axis_rq.tready != 0 || !fAxiRq.notEmpty) begin
	 rqBackpressure <= False;
	 let count = rqBackpressureCycles;
	 count[15] = ~rqBackpressureCount[15];
	 if (count > 5)
	    rqBackpressureCount <= count;
	 rqBackpressureCountSum <= rqBackpressureCountSum + extend(count);
	 rqBackpressureEvents <= rqBackpressureEvents + 1;
	 probe_rqBackpressure <= False;
	 probe_rqBackpressureCount <= count;
	 probe_rqBackpressureCountSum <= rqBackpressureCountSum + extend(count);
	 probe_rqBackpressureEvents <= rqBackpressureEvents + 1;
      end
      else begin
	 probe_rqBackpressure <= True;
      end
   endrule

   // Drive s_axis_cc
   let cc_txready = (pcie_ep.s_axis_cc.tready != 0 && fAxiCc.notEmpty);

   //(* fire_when_enabled, no_implicit_conditions *)
   rule drive_axi_cc if (cc_txready);
      let info = fAxiCc.first; fAxiCc.deq;
      $display("drive axi_cc, data: %h, keep: %h, last: %h", info.data, info.keep, info.last);
      pcie_ep.s_axis_cc.tvalid(1);
      pcie_ep.s_axis_cc.tlast(pack(info.last));
      pcie_ep.s_axis_cc.tdata(info.data);
      pcie_ep.s_axis_cc.tkeep(info.keep);
      pcie_ep.s_axis_cc.tuser(0);
   endrule

   (* fire_when_enabled, no_implicit_conditions *)
   rule drive_axi_cc2 if (!cc_txready);
      pcie_ep.s_axis_cc.tvalid(0);
      pcie_ep.s_axis_cc.tlast(0);
      pcie_ep.s_axis_cc.tdata(0);
      pcie_ep.s_axis_cc.tkeep(0);
      pcie_ep.s_axis_cc.tuser(0);
   endrule

   (* fire_when_enabled, no_implicit_conditions *)
   rule drive_axi_rc_ready;
      pcie_ep.m_axis_rc.tready (duplicate (pack (fAxiRc.notFull)));
   endrule

   // Drive m_axis_rc
   (* fire_when_enabled *)
   rule sink_axi_rc if (pcie_ep.m_axis_rc.tvalid != 0 && fAxiRc.notFull);
      let rc = AxiStRc {data:pcie_ep.m_axis_rc.tdata,
			sop: unpack (pcie_ep.m_axis_rc.tuser [32]),         // tuser.is_sof_0
			eop: unpack (pcie_ep.m_axis_rc.tlast),
			keep:pcie_ep.m_axis_rc.tkeep,
			be:  truncate (pcie_ep.m_axis_rc.tuser [31:0])};    // tuser.byte_en
      fAxiRc.enq (rc);
   endrule

   (* fire_when_enabled, no_implicit_conditions *)
   rule drive_axi_cq_ready;
      pcie_ep.m_axis_cq.tready (duplicate (pack (fAxiCq.notFull)));
   endrule

   (* fire_when_enabled *)
   rule sink_axi_cq if (pcie_ep.m_axis_cq.tvalid != 0 && fAxiCq.notFull);
      let cq = AxiStCq {data:     pcie_ep.m_axis_cq.tdata,
			sop:      unpack (pcie_ep.m_axis_cq.tuser [40]),  // tuser.sop
			eop:      unpack (pcie_ep.m_axis_cq.tlast),
			keep:     pcie_ep.m_axis_cq.tkeep,
			first_be: pcie_ep.m_axis_cq.tuser [3:0],    // tuser.first_be,
			last_be:  pcie_ep.m_axis_cq.tuser [7:4]};   // tuser.last_be
      fAxiCq.enq (cq);
   endrule

   // CQ.
   CQDescriptor cq_desc = unpack(fAxiCq.first.data [127:0]);

   rule rl_cq_wr_header (fAxiCq.first.sop && ((cq_desc.reqtype == MEMORY_WRITE) || (cq_desc.reqtype == IO_WRITE)));
      Bit#(32) data = fAxiCq.first.data[159:128];
      // get data;
      TLPData#(16) tlp16 = convertCQDescriptorToTLP16(cq_desc, data, fAxiCq.first.first_be, fAxiCq.first.last_be);
      $display("cq_desc.reqtype=%h", cq_desc.reqtype);
      // enqueue?
      fcq.enq(tlp16);
      fAxiCq.deq;
   endrule

   // Write data payload, no data remaining
   rule rl_cq_wr_payload((!fAxiCq.first.sop));
      fAxiCq.deq;
   endrule

   // Write data payload, 1 to 3 DWs remaining
   // Write data payload, 4 or more DWs remaining

   rule rl_cq_rd_header (fAxiCq.first.sop && ((cq_desc.reqtype == MEMORY_READ) || (cq_desc.reqtype == IO_READ)));
      Bit#(32) data = 0;
      TLPData#(16) tlp16 = convertCQDescriptorToTLP16(cq_desc, data, fAxiCq.first.first_be, fAxiCq.first.last_be);
      $display("rl_cq_rd_header: cq_desc = %16x", cq_desc);
      fcq.enq(tlp16);
      fAxiCq.deq;
   endrule

   // RC.
   Reg#(DWCount) rc_dwcount <- mkRegU(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   Reg#(Bool) rc_even <- mkReg(True, clocked_by pcie_ep.user_clk, reset_by user_reset_n);

   rule rl_rc_header (fAxiRc.first.sop && rc_even);
      RCDescriptor rc_desc = unpack(fAxiRc.first.data [95:0]);
      // RC descriptor always 96 bytes with first data word in bits 127:96
      Bit#(32) data = byteSwap(fAxiRc.first.data[127:96]);
      TLPData#(16) tlp16 = convertRCDescriptorToTLP16(rc_desc, data);
      rc_dwcount <= (rc_desc.dwcount == 0) ? 0 : rc_desc.dwcount - 1;
      frc.enq(tlp16);
      let even = False;
      if (rc_desc.dwcount == 0 || rc_desc.dwcount == 1) begin
        fAxiRc.deq;
        even = True;
      end
      rc_even <= even;
   endrule

   rule rl_rc_data ((!rc_even || !(fAxiRc.first.sop)) && (rc_dwcount != 0));
      Bit#(16) be16;
      case (rc_dwcount)
         1: be16 = 16'hF000;
         2: be16 = 16'hFF00;
         3: be16 = 16'hFFF0;
         default: be16 = 16'hFFFF;
      endcase
      let last = (rc_dwcount <= 4);
      let dwcount = rc_dwcount - 4;
      if (last) dwcount = 0;
      let data = (rc_even) ? fAxiRc.first.data[127:0]: fAxiRc.first.data[255:128];
      TLPData#(16) tlp16 = TLPData{sof: False,
                                   eof: last,
                                   hit: 0,
                                   be: be16,
                                   data: pack(data)};
      frc.enq(tlp16);
      if (last || !rc_even) begin
         fAxiRc.deq;
      end
      rc_dwcount <= dwcount;
      rc_even <= (last) ? True : !rc_even;
   endrule

   Reg#(DWCount) cc_dwcount <- mkReg(0, clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   FIFOF#(TLPData#(16)) fcc_tlps <- mkFIFOF (clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   // CC.
   rule get_cc_tlps;
      let tlp <- toGet(fcc).get;
      fcc_tlps.enq(tlp);
   endrule

   rule rl_cc_header(fcc_tlps.first.sof);
      match { .cc_desc, .dw} = convertTLP16ToCCDescriptor(fcc_tlps.first);
      cc_dwcount <= cc_desc.dwcount - 1;
      fAxiCc.enq(AxiStCc {data: zeroExtend({dw, pack(cc_desc)[95:0]}),
                       last: fcc_tlps.first.eof,
                       keep: 8'h0F});
      fcc_tlps.deq;
   endrule

   rule rl_cc_data((!fcc_tlps.first.sof) && (cc_dwcount != 0));
      Bit#(256) x = zeroExtend(fcc_tlps.first.data); //FIXME
      fAxiCc.enq(AxiStCc {data: {x},
                       last: cc_dwcount <= 4,
                       keep: (cc_dwcount == 3) ? 8'h0F : 8'hFF});
      fcc_tlps.deq;
   endrule

   // RQ.
   FIFOF#(TLPData#(16)) frq_tlps <- mkFIFOF (clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   Reg#(Bit#(4)) rq_first_be <- mkReg(0, clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   Reg#(Bit#(4)) rq_last_be <- mkReg(0, clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   Reg#(Bool)    rq_even    <- mkRegU(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   Reg#(DWCount) rq_dwcount <- mkReg(0, clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   Reg#(AxiStRq) rq_rq <- mkRegU(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   rule rl_rq_tlps;
      let tlp <- toGet(frq).get;
      frq_tlps.enq(tlp);
   endrule

   rule rl_rq_header if (frq_tlps.first.sof);
      TLPData#(16) tlp <- toGet(frq_tlps).get();
      match { .rq_desc, .first_be, .last_be, .mdata} = convertTLP16ToRQDescriptor(tlp);

      let dwcount = ((rq_desc.reqtype == MEMORY_WRITE) ? rq_desc.dwcount : 0);
      rq_dwcount <= dwcount;
      rq_even <= False;
      rq_first_be <= first_be;
      rq_last_be <= last_be;
      let last = (rq_desc.reqtype == MEMORY_WRITE) ? (dwcount <= 4) : True;
      let rq = AxiStRq {data: zeroExtend(pack(rq_desc)), //FIXME:
			last: last,
			keep: 8'h0F,
			first_be: first_be,
			last_be: last_be};
      if (rq_desc.reqtype == MEMORY_WRITE)
	 rq_rq <= rq;
      else
	 fAxiRq.enq(rq);
   endrule

   // more data
   rule rl_rq_data if (rq_dwcount != 0);
      TLPData#(16) tlp <- toGet(frq_tlps).get();
      let rq = rq_rq;
      let last = (rq_dwcount <= 4);
      let dwcount = rq_dwcount - 4;
      Bit#(8) keep;
      if (last)
	dwcount = 0;
      if (rq_even) begin
	 rq.data[127:0] = tlp.data;
	case (rq_dwcount)
	   1: keep = 8'h01;
	   2: keep = 8'h03;
	   3: keep = 8'h07;
	   default: keep = 8'h0f;
	endcase
      end
      else begin
	rq.data[255:128] = tlp.data;
	case (rq_dwcount)
	   1: keep = 8'h1f;
	   2: keep = 8'h3f;
	   3: keep = 8'h7f;
	   default: keep = 8'hff;
	endcase
      end
      rq.last = last;
      rq.first_be = rq_first_be;
      rq.last_be = rq_last_be;
      rq.keep = keep;
      if (!rq_even || last)
	 fAxiRq.enq(rq);
      if (rq_even)
	rq_rq <= rq;
      rq_dwcount <= dwcount;
      rq_even <= (last) ? False : !rq_even;
   endrule

   FIFO#(Bool) intrMutex <- mkFIFO1(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   Wire#(Bool) msix_int_enable <- mkDWire(False, clocked_by pcie_ep.user_clk, reset_by user_reset_n);

   rule rl_intr;
      if (pcie_ep.cfg.interrupt_msix_enable[0] == 1) begin
	 match { .addr, .data } <- toGet(intrFifo).get();
	 pcie_ep.cfg.interrupt_msix_address(addr);
	 pcie_ep.cfg.interrupt_msix_data(data);
	 msix_int_enable <= True;
	 intrMutex.enq(True);
      end
   endrule: rl_intr
   rule rl_intr_enable;
      pcie_ep.cfg.interrupt_msix_int(pack(msix_int_enable));
   endrule

   rule rl_intr_sent if (pcie_ep.cfg.interrupt_msix_sent() == 1|| pcie_ep.cfg.interrupt_msix_fail() == 1);
      intrMutex.deq();
   endrule

   let probe_current_speed <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_dpa_substate_change <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_err_cor_out <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_err_fatal_out <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_err_nonfatal_out <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_flr_in_process <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_function_power_state <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_function_status <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_hot_reset_out <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_link_power_state <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_ltr_enable <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_ltssm_state <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_max_payload <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_max_read_req <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_negotiated_width <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_obff_enable <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_phy_link_down <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_phy_link_status <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_pl_status_change <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_power_state_change_interrupt <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_rcb_status <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_tph_requester_enable <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_tph_st_mode <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_rq_seq_num <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_rq_seq_num_vld <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   rule rl_drive_probes;
      probe_current_speed <= pcie_ep.cfg.current_speed;
      probe_dpa_substate_change <= pcie_ep.cfg.dpa_substate_change;
      probe_err_cor_out <= pcie_ep.cfg.err_cor_out;
      probe_err_fatal_out <= pcie_ep.cfg.err_fatal_out;
      probe_err_nonfatal_out <= pcie_ep.cfg.err_nonfatal_out;
      probe_flr_in_process <= pcie_ep.cfg.flr_in_process;
      probe_function_power_state <= pcie_ep.cfg.function_power_state;
      probe_function_status <= pcie_ep.cfg.function_status;
      probe_hot_reset_out <= pcie_ep.cfg.hot_reset_out;
      probe_link_power_state <= pcie_ep.cfg.link_power_state;
      probe_ltr_enable <= pcie_ep.cfg.ltr_enable;
      probe_ltssm_state <= pcie_ep.cfg.ltssm_state;
      probe_max_payload <= pcie_ep.cfg.max_payload;
      probe_max_read_req <= pcie_ep.cfg.max_read_req;
      probe_negotiated_width <= pcie_ep.cfg.negotiated_width;
      probe_obff_enable <= pcie_ep.cfg.obff_enable;
      probe_phy_link_down <= pcie_ep.cfg.phy_link_down;
      probe_phy_link_status <= pcie_ep.cfg.phy_link_status;
      probe_pl_status_change <= pcie_ep.cfg.pl_status_change;
      probe_power_state_change_interrupt <= pcie_ep.cfg.power_state_change_interrupt;
      probe_rcb_status <= pcie_ep.cfg.rcb_status;
      probe_tph_requester_enable <= pcie_ep.cfg.tph_requester_enable;
      probe_tph_st_mode <= pcie_ep.cfg.tph_st_mode;

      probe_rq_seq_num <= pcie_ep.pcie.rq_seq_num;
      probe_rq_seq_num_vld <= pcie_ep.pcie.rq_seq_num_vld;
   endrule

   Reg#(Bit#(32)) cyclesReg <- mkReg(0, clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   rule rl_cycles;
      cyclesReg <= cyclesReg + 1;
   endrule

   module mkChangeSource#(Tuple2#(Pcie3CfgType,Bit#(24)) tpl)(PipeOut#(RegChange));
      match { .src, .v } = tpl;
      let snapshot <- mkReg(0);
      let changeFifo <- mkFIFOF1();
      let probe_snapshot <- mkProbe();
      rule rl_update if (v != snapshot);
	 if (changeFifo.notFull) begin
	    changeFifo.enq(RegChange { timestamp: cyclesReg, src: extend(pack(src)), value: extend(v) });
	    snapshot <= v;
	    probe_snapshot <= v;
	 end
      endrule
      return toPipeOut(changeFifo);
   endmodule

`ifndef FOO
   Vector#(22,Tuple2#(Pcie3CfgType,Bit#(24))) changeValues = vec(tuple2(Pcie3Cfg_current_speed, extend(pcie_ep.cfg.current_speed)),
      tuple2(Pcie3Cfg_dpa_substate_change, extend(pcie_ep.cfg.dpa_substate_change)),
      tuple2(Pcie3Cfg_err_cor_out, extend(pcie_ep.cfg.err_cor_out)),
      tuple2(Pcie3Cfg_err_fatal_out, extend(pcie_ep.cfg.err_fatal_out)),
      tuple2(Pcie3Cfg_err_nonfatal_out, extend(pcie_ep.cfg.err_nonfatal_out)),
      tuple2(Pcie3Cfg_flr_in_process, extend(pcie_ep.cfg.flr_in_process)),
      tuple2(Pcie3Cfg_function_power_state, extend(pcie_ep.cfg.function_power_state)),
      tuple2(Pcie3Cfg_function_status, extend(pcie_ep.cfg.function_status)),
      tuple2(Pcie3Cfg_hot_reset_out, extend(pcie_ep.cfg.hot_reset_out)),
      tuple2(Pcie3Cfg_link_power_state, extend(pcie_ep.cfg.link_power_state)),
      tuple2(Pcie3Cfg_ltr_enable, extend(pcie_ep.cfg.ltr_enable)),
      tuple2(Pcie3Cfg_ltssm_state, extend(pcie_ep.cfg.ltssm_state)),
      tuple2(Pcie3Cfg_max_payload, extend(pcie_ep.cfg.max_payload)),
      tuple2(Pcie3Cfg_max_read_req, extend(pcie_ep.cfg.max_read_req)),
      tuple2(Pcie3Cfg_negotiated_width, extend(pcie_ep.cfg.negotiated_width)),
      tuple2(Pcie3Cfg_obff_enable, extend(pcie_ep.cfg.obff_enable)),
      tuple2(Pcie3Cfg_phy_link_down, extend(pcie_ep.cfg.phy_link_down)),
      tuple2(Pcie3Cfg_phy_link_status, extend(pcie_ep.cfg.phy_link_status)),
      tuple2(Pcie3Cfg_pl_status_change, extend(pcie_ep.cfg.pl_status_change)),
      tuple2(Pcie3Cfg_power_state_change_interrupt, extend(pcie_ep.cfg.power_state_change_interrupt)),
      tuple2(Pcie3Cfg_rcb_status, extend(pcie_ep.cfg.rcb_status)),
      tuple2(Pcie3Cfg_rq_backpressure, extend(rqBackpressureCount)));
   let change_pipes <- mapM(mkChangeSource, changeValues, clocked_by pcie_ep.user_clk, reset_by user_reset_n);

   FunnelPipe#(1,22,RegChange,3) changePipe <- mkFunnelPipesPipelined(change_pipes, clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   FIFOF#(RegChange) changeFifo <- mkSizedBRAMFIFOF(128, clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   mkConnection(changePipe[0], toPipeIn(changeFifo), clocked_by pcie_ep.user_clk, reset_by user_reset_n);
`else
   let cs <- mkChangeSource(tuple2(Pcie3Cfg_rq_backpressure, extend(rqBackpressureCount)), clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   FIFOF#(RegChange) changeFifo <- mkSizedBRAMFIFOF(128, clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   mkConnection(cs, toPipeIn(changeFifo), clocked_by pcie_ep.user_clk, reset_by user_reset_n);
`endif

   rule rl_drive_cfg_status_if;
      pcie_ep.cfg.config_space_enable(1);
      pcie_ep.cfg.dsn(64'hf001ba7700000000);
      pcie_ep.cfg.ds_bus_number(0);
      pcie_ep.cfg.ds_device_number(0);
      pcie_ep.cfg.ds_port_number(0);
      pcie_ep.cfg.err_cor_in(0);
      pcie_ep.cfg.err_uncor_in(0);
      pcie_ep.cfg.flr_done(0);
      pcie_ep.cfg.hot_reset_in(0);
      pcie_ep.cfg.link_training_enable(1);
      pcie_ep.cfg.per_function_number(0);
      pcie_ep.cfg.per_function_output_request(0);
      pcie_ep.cfg.power_state_change_ack(0);
      pcie_ep.cfg.subsys_vend_id(16'h1be8);
      pcie_ep.cfg.vf_flr_done(0);

      pcie_ep.pcie.cq_np_req(1);

      pcie_ep.cfg_req_pm_transition.l23_ready(0);
   endrule

   // The PCIE endpoint is processing Gen3 descriptors at 250MHz. The
   // AXI bridge is accepting TLPData#(16)s at 250 MHz. The
   // conversion uses half of Gen3 descriptor.
   //mkConnection(tlp8, gb.tlp, clocked_by portalClock, reset_by portalReset);

   let portalClock = (mainClockPeriod == pcieClockPeriod) ? pcieClock250 : mainClock;
   let portalReset = (mainClockPeriod == pcieClockPeriod) ? pcieReset250 : mainReset;

   interface Server tlpr;
      interface request = toPut(frq);
      interface response = toGet(frc);
   endinterface
   // Requests from other PCIe devices
   interface Server tlpc;
      interface request = toPut(fcc);
      interface response = toGet(fcq);
   endinterface
   interface interruptRequest = toPut(intrFifo);
   interface pcie    = pcie_ep.pci_exp;
   interface Pcie3wrapUser user = pcie_ep.user;
   interface PciewrapPipe pipe = pcie_ep.pipe;
   interface PciewrapCommon common= pcie_ep.common;
   interface regChanges = mapPipe(pack, toPipeOut(changeFifo));
   interface Clock epPcieClock = pcieClock250;
   interface Reset epPcieReset = pcieReset250;
   interface Clock epPortalClock = portalClock;
   interface Reset epPortalReset = portalReset;
   interface Clock epDerivedClock = derivedClock;
   interface Reset epDerivedReset = derivedReset;
endmodule: mkPcieEndpointX7

endpackage: Pcie3EndpointX7

// Copyright (c) 2014-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.

package Pcie3EndpointX7;

import BRAMFIFO          ::*;
import Clocks            ::*;
import Vector            ::*;
import BuildVector       ::*;
import Connectable       ::*;
import GetPut            ::*;
import Reserved          ::*;
import TieOff            ::*;
import DefaultValue      ::*;
import DReg              ::*;
import Gearbox           ::*;
import FIFO              ::*;
import FIFOF             ::*;
import CFFIFO            ::*;
import SpecialFIFOs      ::*;
import ClientServer      ::*;
import Real              ::*;
import XilinxVirtex7PCIE ::*;
import BUtils            ::*;
import Probe             ::*;

import ConnectalConfig::*;
import ConnectalClocks   ::*;
import ConnectalXilinxCells   ::*;
import XilinxCells       ::*;
import PCIE              ::*;
import PCIEWRAPPER3      ::*;
import Bufgctrl           ::*;
import PcieGearbox       :: *;
import Pipe              :: *;

interface PcieEndpointX7#(numeric type lanes);
   interface PciewrapPci_exp#(lanes)           pcie;
   interface PciewrapUser#(lanes)              user;
   interface PciewrapPipe#(lanes)              pipe;
   interface PciewrapCommon#(lanes)            common;
   interface Server#(TLPData#(16), TLPData#(16)) tlpr;
   interface Server#(TLPData#(16), TLPData#(16)) tlpc;
   interface Put#(Tuple2#(Bit#(64),Bit#(32)))  interruptRequest;
   interface PipeOut#(Bit#(64)) regChanges;
   interface Clock epPcieClock;
   interface Reset epPcieReset;
   interface Clock epPortalClock;
   interface Reset epPortalReset;
   interface Clock epDerivedClock;
   interface Reset epDerivedReset;
endinterface

typedef struct {
   Bit #(256)     data;
   Bool          sop;
   Bool          eop;
   Bit #(8)      keep;
   TLPFirstDWBE  first_be;
   TLPFirstDWBE  last_be;
} AxiStCq deriving (Bits, Eq);

typedef struct {
   Bit #(256)     data;
   Bit #(8)      keep;
   Bool          last;
} AxiStCc deriving (Bits, Eq);

typedef struct {
   Bit #(256)     data;
   Bool          last;
   Bit #(8)      keep;
   Bit #(4)      first_be;
   Bit #(4)      last_be;
} AxiStRq deriving (Bits, Eq);

typedef struct {
   Bit #(256)     data;
   Bool          sop;
   Bool          eop;
   Bit #(8)      keep;
   Bit #(8)      be;
} AxiStRc deriving (Bits, Eq);

function TLPData#(16) convertCQDescriptorToTLP16(CQDescriptor desc, Bit#(32) data, TLPFirstDWBE first, TLPLastDWBE last);
   TLPMemoryIO3DWHeader header = defaultValue;
   header.format     = tpl_1(convertCQReqTypeToTLPFmtType(desc.reqtype));
   header.pkttype    = tpl_2(convertCQReqTypeToTLPFmtType(desc.reqtype));
   header.tclass     = desc.tclass;
   header.relaxed    = desc.relaxed;
   header.nosnoop    = desc.nosnoop;
   header.length     = (desc.dwcount == 1024) ? 0 : truncate(desc.dwcount);
   header.reqid      = desc.reqid;
   header.tag        = desc.tag;
   header.lastbe     = last;
   header.firstbe    = first;
   header.addr       = truncate(desc.address);
   header.data       = convertDW(data);

   Bool is3DW = isReadReqType(desc.reqtype);
   Bool is3Or4DW = isReadReqType(desc.reqtype) || (desc.dwcount == 1);

   TLPData#(16) retval = defaultValue;
   retval.sof   = True;
   retval.eof   = is3Or4DW;
   retval.hit   = (1 << pack(desc.barid));
   retval.data  = pack(header);
   retval.be    = (is3DW ? 16'hFFF0 : 16'hFFFF);

   return retval;
endfunction

function TLPData#(16) convertRCDescriptorToTLP16(RCDescriptor desc, Bit#(32) data);
   TLPCompletionHeader header = defaultValue;
   header.tclass    = desc.tclass;
   header.relaxed   = desc.relaxed;
   header.nosnoop   = desc.nosnoop;
   header.cmplid    = desc.complid;
   header.tag       = desc.tag;
   header.reqid     = desc.reqid;
   header.poison    = desc.poisoned;
   header.cstatus   = desc.status;
   header.length    = (desc.dwcount == 1024) ? 0 : truncate(desc.dwcount);
   header.bytecount = (desc.bytecount == 4096) ? 0 : truncate(desc.bytecount);
   header.loweraddr = truncate(desc.loweraddr);
   header.data      = convertDW(data);

   Bool is3DW = (desc.dwcount == 0);
   Bool is3Or4DW = (desc.dwcount == 0) || (desc.dwcount == 1);
   TLPData#(16) retval = defaultValue;
   retval.sof   = True;
   retval.eof   = is3Or4DW;
   retval.hit   = 1; // XXX
   retval.data  = pack(header);
   retval.be    = (is3DW ? 16'hFFF0 : 16'hFFFF);

   return retval;
endfunction

typedef struct {
   Bit#(32) timestamp;
   Bit#(8) src;
   Bit#(24) value;
} RegChange deriving (Bits);

typedef enum {
   Pcie3Cfg_none,
   Pcie3Cfg_current_speed,
   Pcie3Cfg_dpa_substate_change,
   Pcie3Cfg_err_cor_out,
   Pcie3Cfg_err_fatal_out,
   Pcie3Cfg_err_nonfatal_out,
   Pcie3Cfg_flr_in_process,
   Pcie3Cfg_function_power_state,
   Pcie3Cfg_function_status,
   Pcie3Cfg_hot_reset_out,
   Pcie3Cfg_link_power_state,
   Pcie3Cfg_ltr_enable,
   Pcie3Cfg_ltssm_state,
   Pcie3Cfg_max_payload,
   Pcie3Cfg_max_read_req,
   Pcie3Cfg_negotiated_width,
   Pcie3Cfg_obff_enable,
   Pcie3Cfg_phy_link_down,
   Pcie3Cfg_phy_link_status,
   Pcie3Cfg_pl_status_change,
   Pcie3Cfg_power_state_change_interrupt,
   Pcie3Cfg_rcb_status,
   Pcie3Cfg_rq_backpressure
   } Pcie3CfgType deriving (Bits,Eq);

(* synthesize *)
module mkPcieEndpointX7(PcieEndpointX7#(PcieLanes));

   PCIEParams params = defaultValue;
   Clock defaultClock <- exposeCurrentClock();
   Reset defaultReset <- exposeCurrentReset();
   Reset defaultResetInverted <- mkResetInverter(defaultReset, clocked_by defaultClock);
   PcieWrap#(PcieLanes) pcie_ep <- mkPcieWrap(defaultClock, defaultResetInverted);

   // The PCIe endpoint exports full (250MHz) and half-speed (125MHz) clocks
   Clock pcieClock250 = pcie_ep.user_clk;
   Reset user_reset_n <- mkResetInverter(pcie_ep.user_reset, clocked_by pcie_ep.user_clk);
   Reset pcieReset250 <- mkAsyncReset(4, user_reset_n, pcieClock250);

   ClockGenerator7Params     clkgenParams = defaultValue;
   clkgenParams.clkin1_period    = 4.000; //  250MHz
   clkgenParams.clkin1_period    = 4.000;
   clkgenParams.clkin_buffer     = False;
   clkgenParams.clkfbout_mult_f  = 4.000; // 1000MHz
   clkgenParams.clkout0_divide_f = derivedClockPeriod;
   clkgenParams.clkout1_divide     = round(mainClockPeriod);
   clkgenParams.clkout1_duty_cycle = 0.5;
   clkgenParams.clkout1_phase      = 0.0000;
   ClockGenerator7           clkgen <- mkClockGenerator7(clkgenParams, clocked_by pcieClock250, reset_by pcieReset250);
   Clock mainClock = clkgen.clkout1;
   Reset mainReset <- mkAsyncReset(4, pcieReset250, mainClock);
   Clock derivedClock = clkgen.clkout0;
   Reset derivedReset <- mkAsyncReset(4, pcieReset250, derivedClock);
   Reset user_reset <- mkAsyncReset(2, pcie_ep.user_reset, pcie_ep.user_clk);

   // FIFOS
   FIFOF#(AxiStCq) fAxiCq <- mkFIFOF(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   FIFOF#(AxiStRc) fAxiRc <- mkCFFIFOF(clocked_by pcie_ep.user_clk, reset_by user_reset_n);

   FIFOF#(AxiStRq) fAxiRq <- mkCFFIFOF(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   FIFOF#(AxiStCc) fAxiCc <- mkFIFOF(clocked_by pcie_ep.user_clk, reset_by user_reset_n);

   FIFOF#(TLPData#(16)) fcq <- mkFIFOF(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   FIFOF#(TLPData#(16)) frc <- mkFIFOF(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   FIFOF#(TLPData#(16)) fcc <- mkFIFOF(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   FIFOF#(TLPData#(16)) frq <- mkFIFOF(clocked_by pcie_ep.user_clk, reset_by user_reset_n);

   FIFOF#(Tuple2#(Bit#(64),Bit#(32))) intrFifo <- mkFIFOF(clocked_by pcie_ep.user_clk, reset_by user_reset_n);

   // Drive s_axis_rq
   let rq_txready = (pcie_ep.s_axis_rq.tready != 0 && fAxiRq.notEmpty);

   //(* fire_when_enabled, no_implicit_conditions *)
   rule drive_axi_rq if (rq_txready);
      let info = fAxiRq.first; fAxiRq.deq;
      pcie_ep.s_axis_rq.tvalid(1);
      pcie_ep.s_axis_rq.tlast(pack(info.last));
      pcie_ep.s_axis_rq.tdata(info.data);
      pcie_ep.s_axis_rq.tkeep(info.keep);
      pcie_ep.s_axis_rq.tuser({0, info.last_be, info.first_be});
   endrule

   (* fire_when_enabled, no_implicit_conditions *)
   rule drive_axi_rq2 if (!rq_txready);
      pcie_ep.s_axis_rq.tvalid(0);
      pcie_ep.s_axis_rq.tlast(0);
      pcie_ep.s_axis_rq.tdata(0);
      pcie_ep.s_axis_rq.tkeep(0);
      pcie_ep.s_axis_rq.tuser(0);
   endrule

   Reg#(Bit#(16)) rqBackpressureCycles <- mkReg(0, clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   Reg#(Bit#(16)) rqBackpressureCount <- mkReg(0, clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   Reg#(Bool)     rqBackpressure       <- mkReg(False, clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   Reg#(Bit#(32)) rqBackpressureCountSum <- mkReg(0, clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   Reg#(Bit#(32)) rqBackpressureEvents   <- mkReg(0, clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_rqBackpressureCycles <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_rqBackpressureCount <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_rqBackpressure       <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   Probe#(Bit#(32)) probe_rqBackpressureCountSum <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   Probe#(Bit#(32)) probe_rqBackpressureEvents   <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_fAxiRqNotEmpty       <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_SAxsiRqTReady        <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   rule rltready;
      probe_fAxiRqNotEmpty <= fAxiRq.notEmpty();
      probe_SAxsiRqTReady <= pcie_ep.s_axis_rq.tready;
   endrule
   rule rlBackpressureEnter if (!rqBackpressure);
      if (pcie_ep.s_axis_rq.tready == 0 && fAxiRq.notEmpty) begin
	 rqBackpressure <= True;
	 rqBackpressureCycles <= 0;
	 probe_rqBackpressure <= True;
	 probe_rqBackpressureCycles <= 0;
      end
   endrule
   rule rlBackpressureExit if (rqBackpressure);
      rqBackpressureCycles <= rqBackpressureCycles + 1;
      probe_rqBackpressureCycles <= rqBackpressureCycles + 1;
      if (pcie_ep.s_axis_rq.tready != 0 || !fAxiRq.notEmpty) begin
	 rqBackpressure <= False;
	 let count = rqBackpressureCycles;
	 count[15] = ~rqBackpressureCount[15];
	 if (count > 5)
	    rqBackpressureCount <= count;
	 rqBackpressureCountSum <= rqBackpressureCountSum + extend(count);
	 rqBackpressureEvents <= rqBackpressureEvents + 1;
	 probe_rqBackpressure <= False;
	 probe_rqBackpressureCount <= count;
	 probe_rqBackpressureCountSum <= rqBackpressureCountSum + extend(count);
	 probe_rqBackpressureEvents <= rqBackpressureEvents + 1;
      end
      else begin
	 probe_rqBackpressure <= True;
      end
   endrule

   // Drive s_axis_cc
   let cc_txready = (pcie_ep.s_axis_cc.tready != 0 && fAxiCc.notEmpty);

   //(* fire_when_enabled, no_implicit_conditions *)
   rule drive_axi_cc if (cc_txready);
      let info = fAxiCc.first; fAxiCc.deq;
      $display("drive axi_cc, data: %h, keep: %h, last: %h", info.data, info.keep, info.last);
      pcie_ep.s_axis_cc.tvalid(1);
      pcie_ep.s_axis_cc.tlast(pack(info.last));
      pcie_ep.s_axis_cc.tdata(info.data);
      pcie_ep.s_axis_cc.tkeep(info.keep);
      pcie_ep.s_axis_cc.tuser(0);
   endrule

   (* fire_when_enabled, no_implicit_conditions *)
   rule drive_axi_cc2 if (!cc_txready);
      pcie_ep.s_axis_cc.tvalid(0);
      pcie_ep.s_axis_cc.tlast(0);
      pcie_ep.s_axis_cc.tdata(0);
      pcie_ep.s_axis_cc.tkeep(0);
      pcie_ep.s_axis_cc.tuser(0);
   endrule

   (* fire_when_enabled, no_implicit_conditions *)
   rule drive_axi_rc_ready;
      pcie_ep.m_axis_rc.tready (duplicate (pack (fAxiRc.notFull)));
   endrule

   // Drive m_axis_rc
   (* fire_when_enabled *)
   rule sink_axi_rc if (pcie_ep.m_axis_rc.tvalid != 0 && fAxiRc.notFull);
      let rc = AxiStRc {data:pcie_ep.m_axis_rc.tdata,
			sop: unpack (pcie_ep.m_axis_rc.tuser [32]),         // tuser.is_sof_0
			eop: unpack (pcie_ep.m_axis_rc.tlast),
			keep:pcie_ep.m_axis_rc.tkeep,
			be:  truncate (pcie_ep.m_axis_rc.tuser [31:0])};    // tuser.byte_en
      fAxiRc.enq (rc);
   endrule

   (* fire_when_enabled, no_implicit_conditions *)
   rule drive_axi_cq_ready;
      pcie_ep.m_axis_cq.tready (duplicate (pack (fAxiCq.notFull)));
   endrule

   (* fire_when_enabled *)
   rule sink_axi_cq if (pcie_ep.m_axis_cq.tvalid != 0 && fAxiCq.notFull);
      let cq = AxiStCq {data:     pcie_ep.m_axis_cq.tdata,
			sop:      unpack (pcie_ep.m_axis_cq.tuser [40]),  // tuser.sop
			eop:      unpack (pcie_ep.m_axis_cq.tlast),
			keep:     pcie_ep.m_axis_cq.tkeep,
			first_be: pcie_ep.m_axis_cq.tuser [3:0],    // tuser.first_be,
			last_be:  pcie_ep.m_axis_cq.tuser [7:4]};   // tuser.last_be
      fAxiCq.enq (cq);
   endrule

   // CQ.
   CQDescriptor cq_desc = unpack(fAxiCq.first.data [127:0]);

   rule rl_cq_wr_header (fAxiCq.first.sop && ((cq_desc.reqtype == MEMORY_WRITE) || (cq_desc.reqtype == IO_WRITE)));
      Bit#(32) data = fAxiCq.first.data[159:128];
      // get data;
      TLPData#(16) tlp16 = convertCQDescriptorToTLP16(cq_desc, data, fAxiCq.first.first_be, fAxiCq.first.last_be);
      $display("cq_desc.reqtype=%h", cq_desc.reqtype);
      // enqueue?
      fcq.enq(tlp16);
      fAxiCq.deq;
   endrule

   // Write data payload, no data remaining
   rule rl_cq_wr_payload((!fAxiCq.first.sop));
      fAxiCq.deq;
   endrule

   // Write data payload, 1 to 3 DWs remaining
   // Write data payload, 4 or more DWs remaining

   rule rl_cq_rd_header (fAxiCq.first.sop && ((cq_desc.reqtype == MEMORY_READ) || (cq_desc.reqtype == IO_READ)));
      Bit#(32) data = 0;
      TLPData#(16) tlp16 = convertCQDescriptorToTLP16(cq_desc, data, fAxiCq.first.first_be, fAxiCq.first.last_be);
      $display("rl_cq_rd_header: cq_desc = %16x", cq_desc);
      fcq.enq(tlp16);
      fAxiCq.deq;
   endrule

   // RC.
   Reg#(DWCount) rc_dwcount <- mkRegU(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   Reg#(Bool) rc_even <- mkReg(True, clocked_by pcie_ep.user_clk, reset_by user_reset_n);

   rule rl_rc_header (fAxiRc.first.sop && rc_even);
      RCDescriptor rc_desc = unpack(fAxiRc.first.data [95:0]);
      // RC descriptor always 96 bytes with first data word in bits 127:96
      Bit#(32) data = byteSwap(fAxiRc.first.data[127:96]);
      TLPData#(16) tlp16 = convertRCDescriptorToTLP16(rc_desc, data);
      rc_dwcount <= (rc_desc.dwcount == 0) ? 0 : rc_desc.dwcount - 1;
      frc.enq(tlp16);
      let even = False;
      if (rc_desc.dwcount == 0 || rc_desc.dwcount == 1) begin
        fAxiRc.deq;
        even = True;
      end
      rc_even <= even;
   endrule

   rule rl_rc_data ((!rc_even || !(fAxiRc.first.sop)) && (rc_dwcount != 0));
      Bit#(16) be16;
      case (rc_dwcount)
         1: be16 = 16'hF000;
         2: be16 = 16'hFF00;
         3: be16 = 16'hFFF0;
         default: be16 = 16'hFFFF;
      endcase
      let last = (rc_dwcount <= 4);
      let dwcount = rc_dwcount - 4;
      if (last) dwcount = 0;
      let data = (rc_even) ? fAxiRc.first.data[127:0]: fAxiRc.first.data[255:128];
      TLPData#(16) tlp16 = TLPData{sof: False,
                                   eof: last,
                                   hit: 0,
                                   be: be16,
                                   data: pack(data)};
      frc.enq(tlp16);
      if (last || !rc_even) begin
         fAxiRc.deq;
      end
      rc_dwcount <= dwcount;
      rc_even <= (last) ? True : !rc_even;
   endrule

   Reg#(DWCount) cc_dwcount <- mkReg(0, clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   FIFOF#(TLPData#(16)) fcc_tlps <- mkFIFOF (clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   // CC.
   rule get_cc_tlps;
      let tlp <- toGet(fcc).get;
      fcc_tlps.enq(tlp);
   endrule

   rule rl_cc_header(fcc_tlps.first.sof);
      match { .cc_desc, .dw} = convertTLP16ToCCDescriptor(fcc_tlps.first);
      cc_dwcount <= cc_desc.dwcount - 1;
      fAxiCc.enq(AxiStCc {data: zeroExtend({dw, pack(cc_desc)[95:0]}),
                       last: fcc_tlps.first.eof,
                       keep: 8'h0F});
      fcc_tlps.deq;
   endrule

   rule rl_cc_data((!fcc_tlps.first.sof) && (cc_dwcount != 0));
      Bit#(256) x = zeroExtend(fcc_tlps.first.data); //FIXME
      fAxiCc.enq(AxiStCc {data: {x},
                       last: cc_dwcount <= 4,
                       keep: (cc_dwcount == 3) ? 8'h0F : 8'hFF});
      fcc_tlps.deq;
   endrule

   // RQ.
   FIFOF#(TLPData#(16)) frq_tlps <- mkFIFOF (clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   Reg#(Bit#(4)) rq_first_be <- mkReg(0, clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   Reg#(Bit#(4)) rq_last_be <- mkReg(0, clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   Reg#(Bool)    rq_even    <- mkRegU(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   Reg#(DWCount) rq_dwcount <- mkReg(0, clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   Reg#(AxiStRq) rq_rq <- mkRegU(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   rule rl_rq_tlps;
      let tlp <- toGet(frq).get;
      frq_tlps.enq(tlp);
   endrule

   rule rl_rq_header if (frq_tlps.first.sof);
      TLPData#(16) tlp <- toGet(frq_tlps).get();
      match { .rq_desc, .first_be, .last_be, .mdata} = convertTLP16ToRQDescriptor(tlp);

      let dwcount = ((rq_desc.reqtype == MEMORY_WRITE) ? rq_desc.dwcount : 0);
      rq_dwcount <= dwcount;
      rq_even <= False;
      rq_first_be <= first_be;
      rq_last_be <= last_be;
      let last = (rq_desc.reqtype == MEMORY_WRITE) ? (dwcount <= 4) : True;
      let rq = AxiStRq {data: zeroExtend(pack(rq_desc)), //FIXME:
			last: last,
			keep: 8'h0F,
			first_be: first_be,
			last_be: last_be};
      if (rq_desc.reqtype == MEMORY_WRITE)
	 rq_rq <= rq;
      else
	 fAxiRq.enq(rq);
   endrule

   // more data
   rule rl_rq_data if (rq_dwcount != 0);
      TLPData#(16) tlp <- toGet(frq_tlps).get();
      let rq = rq_rq;
      let last = (rq_dwcount <= 4);
      let dwcount = rq_dwcount - 4;
      Bit#(8) keep;
      if (last)
	dwcount = 0;
      if (rq_even) begin
	 rq.data[127:0] = tlp.data;
	case (rq_dwcount)
	   1: keep = 8'h01;
	   2: keep = 8'h03;
	   3: keep = 8'h07;
	   default: keep = 8'h0f;
	endcase
      end
      else begin
	rq.data[255:128] = tlp.data;
	case (rq_dwcount)
	   1: keep = 8'h1f;
	   2: keep = 8'h3f;
	   3: keep = 8'h7f;
	   default: keep = 8'hff;
	endcase
      end
      rq.last = last;
      rq.first_be = rq_first_be;
      rq.last_be = rq_last_be;
      rq.keep = keep;
      if (!rq_even || last)
	 fAxiRq.enq(rq);
      if (rq_even)
	rq_rq <= rq;
      rq_dwcount <= dwcount;
      rq_even <= (last) ? False : !rq_even;
   endrule

   FIFO#(Bool) intrMutex <- mkFIFO1(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   Wire#(Bool) msix_int_enable <- mkDWire(False, clocked_by pcie_ep.user_clk, reset_by user_reset_n);

   rule rl_intr;
      if (pcie_ep.cfg.interrupt_msix_enable[0] == 1) begin
	 match { .addr, .data } <- toGet(intrFifo).get();
	 pcie_ep.cfg.interrupt_msix_address(addr);
	 pcie_ep.cfg.interrupt_msix_data(data);
	 msix_int_enable <= True;
	 intrMutex.enq(True);
      end
   endrule: rl_intr
   rule rl_intr_enable;
      pcie_ep.cfg.interrupt_msix_int(pack(msix_int_enable));
   endrule

   rule rl_intr_sent if (pcie_ep.cfg.interrupt_msix_sent() == 1|| pcie_ep.cfg.interrupt_msix_fail() == 1);
      intrMutex.deq();
   endrule

   let probe_current_speed <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_dpa_substate_change <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_err_cor_out <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_err_fatal_out <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_err_nonfatal_out <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_flr_in_process <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_function_power_state <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_function_status <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_hot_reset_out <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_link_power_state <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_ltr_enable <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_ltssm_state <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_max_payload <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_max_read_req <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_negotiated_width <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_obff_enable <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_phy_link_down <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_phy_link_status <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_pl_status_change <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_power_state_change_interrupt <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_rcb_status <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_tph_requester_enable <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_tph_st_mode <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_rq_seq_num <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   let probe_rq_seq_num_vld <- mkProbe(clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   rule rl_drive_probes;
      probe_current_speed <= pcie_ep.cfg.current_speed;
      probe_dpa_substate_change <= pcie_ep.cfg.dpa_substate_change;
      probe_err_cor_out <= pcie_ep.cfg.err_cor_out;
      probe_err_fatal_out <= pcie_ep.cfg.err_fatal_out;
      probe_err_nonfatal_out <= pcie_ep.cfg.err_nonfatal_out;
      probe_flr_in_process <= pcie_ep.cfg.flr_in_process;
      probe_function_power_state <= pcie_ep.cfg.function_power_state;
      probe_function_status <= pcie_ep.cfg.function_status;
      probe_hot_reset_out <= pcie_ep.cfg.hot_reset_out;
      probe_link_power_state <= pcie_ep.cfg.link_power_state;
      probe_ltr_enable <= pcie_ep.cfg.ltr_enable;
      probe_ltssm_state <= pcie_ep.cfg.ltssm_state;
      probe_max_payload <= pcie_ep.cfg.max_payload;
      probe_max_read_req <= pcie_ep.cfg.max_read_req;
      probe_negotiated_width <= pcie_ep.cfg.negotiated_width;
      probe_obff_enable <= pcie_ep.cfg.obff_enable;
      probe_phy_link_down <= pcie_ep.cfg.phy_link_down;
      probe_phy_link_status <= pcie_ep.cfg.phy_link_status;
      probe_pl_status_change <= pcie_ep.cfg.pl_status_change;
      probe_power_state_change_interrupt <= pcie_ep.cfg.power_state_change_interrupt;
      probe_rcb_status <= pcie_ep.cfg.rcb_status;
      probe_tph_requester_enable <= pcie_ep.cfg.tph_requester_enable;
      probe_tph_st_mode <= pcie_ep.cfg.tph_st_mode;

      probe_rq_seq_num <= pcie_ep.pcie.rq_seq_num;
      probe_rq_seq_num_vld <= pcie_ep.pcie.rq_seq_num_vld;
   endrule

   Reg#(Bit#(32)) cyclesReg <- mkReg(0, clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   rule rl_cycles;
      cyclesReg <= cyclesReg + 1;
   endrule

   module mkChangeSource#(Tuple2#(Pcie3CfgType,Bit#(24)) tpl)(PipeOut#(RegChange));
      match { .src, .v } = tpl;
      let snapshot <- mkReg(0);
      let changeFifo <- mkFIFOF1();
      let probe_snapshot <- mkProbe();
      rule rl_update if (v != snapshot);
	 if (changeFifo.notFull) begin
	    changeFifo.enq(RegChange { timestamp: cyclesReg, src: extend(pack(src)), value: extend(v) });
	    snapshot <= v;
	    probe_snapshot <= v;
	 end
      endrule
      return toPipeOut(changeFifo);
   endmodule

`ifndef FOO
   Vector#(22,Tuple2#(Pcie3CfgType,Bit#(24))) changeValues = vec(tuple2(Pcie3Cfg_current_speed, extend(pcie_ep.cfg.current_speed)),
      tuple2(Pcie3Cfg_dpa_substate_change, extend(pcie_ep.cfg.dpa_substate_change)),
      tuple2(Pcie3Cfg_err_cor_out, extend(pcie_ep.cfg.err_cor_out)),
      tuple2(Pcie3Cfg_err_fatal_out, extend(pcie_ep.cfg.err_fatal_out)),
      tuple2(Pcie3Cfg_err_nonfatal_out, extend(pcie_ep.cfg.err_nonfatal_out)),
      tuple2(Pcie3Cfg_flr_in_process, extend(pcie_ep.cfg.flr_in_process)),
      tuple2(Pcie3Cfg_function_power_state, extend(pcie_ep.cfg.function_power_state)),
      tuple2(Pcie3Cfg_function_status, extend(pcie_ep.cfg.function_status)),
      tuple2(Pcie3Cfg_hot_reset_out, extend(pcie_ep.cfg.hot_reset_out)),
      tuple2(Pcie3Cfg_link_power_state, extend(pcie_ep.cfg.link_power_state)),
      tuple2(Pcie3Cfg_ltr_enable, extend(pcie_ep.cfg.ltr_enable)),
      tuple2(Pcie3Cfg_ltssm_state, extend(pcie_ep.cfg.ltssm_state)),
      tuple2(Pcie3Cfg_max_payload, extend(pcie_ep.cfg.max_payload)),
      tuple2(Pcie3Cfg_max_read_req, extend(pcie_ep.cfg.max_read_req)),
      tuple2(Pcie3Cfg_negotiated_width, extend(pcie_ep.cfg.negotiated_width)),
      tuple2(Pcie3Cfg_obff_enable, extend(pcie_ep.cfg.obff_enable)),
      tuple2(Pcie3Cfg_phy_link_down, extend(pcie_ep.cfg.phy_link_down)),
      tuple2(Pcie3Cfg_phy_link_status, extend(pcie_ep.cfg.phy_link_status)),
      tuple2(Pcie3Cfg_pl_status_change, extend(pcie_ep.cfg.pl_status_change)),
      tuple2(Pcie3Cfg_power_state_change_interrupt, extend(pcie_ep.cfg.power_state_change_interrupt)),
      tuple2(Pcie3Cfg_rcb_status, extend(pcie_ep.cfg.rcb_status)),
      tuple2(Pcie3Cfg_rq_backpressure, extend(rqBackpressureCount)));
   let change_pipes <- mapM(mkChangeSource, changeValues, clocked_by pcie_ep.user_clk, reset_by user_reset_n);

   FunnelPipe#(1,22,RegChange,3) changePipe <- mkFunnelPipesPipelined(change_pipes, clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   FIFOF#(RegChange) changeFifo <- mkSizedBRAMFIFOF(128, clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   mkConnection(changePipe[0], toPipeIn(changeFifo), clocked_by pcie_ep.user_clk, reset_by user_reset_n);
`else
   let cs <- mkChangeSource(tuple2(Pcie3Cfg_rq_backpressure, extend(rqBackpressureCount)), clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   FIFOF#(RegChange) changeFifo <- mkSizedBRAMFIFOF(128, clocked_by pcie_ep.user_clk, reset_by user_reset_n);
   mkConnection(cs, toPipeIn(changeFifo), clocked_by pcie_ep.user_clk, reset_by user_reset_n);
`endif

   rule rl_drive_cfg_status_if;
      pcie_ep.cfg.config_space_enable(1);
      pcie_ep.cfg.dsn(64'hf001ba7700000000);
      pcie_ep.cfg.ds_bus_number(0);
      pcie_ep.cfg.ds_device_number(0);
      pcie_ep.cfg.ds_port_number(0);
      pcie_ep.cfg.err_cor_in(0);
      pcie_ep.cfg.err_uncor_in(0);
      pcie_ep.cfg.flr_done(0);
      pcie_ep.cfg.hot_reset_in(0);
      pcie_ep.cfg.link_training_enable(1);
      pcie_ep.cfg.per_function_number(0);
      pcie_ep.cfg.per_function_output_request(0);
      pcie_ep.cfg.power_state_change_ack(0);
      pcie_ep.cfg.subsys_vend_id(16'h1be8);
      pcie_ep.cfg.vf_flr_done(0);

      pcie_ep.pcie.cq_np_req(1);

      pcie_ep.cfg_req_pm_transition.l23_ready(0);
   endrule

   // The PCIE endpoint is processing Gen3 descriptors at 250MHz. The
   // AXI bridge is accepting TLPData#(16)s at 250 MHz. The
   // conversion uses half of Gen3 descriptor.
   //mkConnection(tlp8, gb.tlp, clocked_by portalClock, reset_by portalReset);

   let portalClock = (mainClockPeriod == pcieClockPeriod) ? pcieClock250 : mainClock;
   let portalReset = (mainClockPeriod == pcieClockPeriod) ? pcieReset250 : mainReset;

   interface Server tlpr;
      interface request = toPut(frq);
      interface response = toGet(frc);
   endinterface
   // Requests from other PCIe devices
   interface Server tlpc;
      interface request = toPut(fcc);
      interface response = toGet(fcq);
   endinterface
   interface interruptRequest = toPut(intrFifo);
   interface pcie    = pcie_ep.pci_exp;
   interface Pcie3wrapUser user = pcie_ep.user;
   interface PciewrapPipe pipe = pcie_ep.pipe;
   interface PciewrapCommon common= pcie_ep.common;
   interface regChanges = mapPipe(pack, toPipeOut(changeFifo));
   interface Clock epPcieClock = pcieClock250;
   interface Reset epPcieReset = pcieReset250;
   interface Clock epPortalClock = portalClock;
   interface Reset epPortalReset = portalReset;
   interface Clock epDerivedClock = derivedClock;
   interface Reset epDerivedReset = derivedReset;
endmodule: mkPcieEndpointX7

endpackage: Pcie3EndpointX7