s_axi interface clock and reset

s_axi interface clock and reset

/*
   ../scripts/importbvi.py
   -o
   AxiEthBvi.bsv
   -P
   AxiEthBvi
   -I
   AxiEthBvi
   ../../out/vc709/axi_ethernet_0/axi_ethernet_0_stub.v
*/

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

(* always_ready, always_enabled *)
interface AxiethbviAxi;
    method Action      rxd_arstn(Bit#(1) v);
    method Action      rxs_arstn(Bit#(1) v);
    method Action      txc_arstn(Bit#(1) v);
    method Action      txd_arstn(Bit#(1) v);
endinterface
(* always_ready, always_enabled *)
interface AxiethbviAxis;
    method Action      clk(Bit#(1) v);
endinterface
(* always_ready, always_enabled *)
interface AxiethbviGt;
    method Bit#(1)     qplloutclk_out();
    method Bit#(1)     qplloutrefclk_out();
endinterface
(* always_ready, always_enabled *)
interface AxiethbviGtref;
    method Bit#(1)     clk_buf_out();
    method Bit#(1)     clk_out();
endinterface
(* always_ready, always_enabled *)
interface AxiethbviMac;
    method Bit#(1)     irq();
endinterface
(* always_ready, always_enabled *)
interface AxiethbviMdio;
    method Bit#(1)     mdc();
    method Action      mdio_i(Bit#(1) v);
    method Bit#(1)     mdio_o();
    method Bit#(1)     mdio_t();
endinterface
(* always_ready, always_enabled *)
interface AxiethbviMgt;
    method Action      clk_clk_n(Bit#(1) v);
    method Action      clk_clk_p(Bit#(1) v);
endinterface
(* always_ready, always_enabled *)
interface AxiethbviMmcm;
    method Bit#(1)     locked_out();
endinterface
(* always_ready, always_enabled *)
interface AxiethbviPhy;
    method Bit#(1)     rst_n();
endinterface
(* always_ready, always_enabled *)
interface AxiethbviPma;
    method Bit#(1)     reset_out();
endinterface
(* always_ready, always_enabled *)
interface AxiethbviRef;
    method Action      clk(Bit#(1) v);
endinterface
(* always_ready, always_enabled *)
interface AxiethbviRxuserclk;
    method Bit#(1)     out();
endinterface
(* always_ready, always_enabled *)
interface AxiethbviS_axi;
    method Action      araddr(Bit#(18) v);
    method Bit#(1)     arready();
    method Action      arvalid(Bit#(1) v);
    method Action      awaddr(Bit#(18) 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 *)
interface AxiethbviSgmii;
    method Action      rxn(Bit#(1) v);
    method Action      rxp(Bit#(1) v);
    method Bit#(1)     txn();
    method Bit#(1)     txp();
endinterface
(* always_ready, always_enabled *)
interface AxiethbviSignal;
    method Action      detect(Bit#(1) v);
endinterface
(* always_ready, always_enabled *)
interface AxiethbviUserclk;
    method Bit#(1)     out();
endinterface
(* always_ready, always_enabled *)
interface AxiEthBvi;
    interface AxiethbviAxi     axi;
    interface AxiethbviAxis     axis;
    interface AxiethbviGt     gt0;
    interface AxiethbviGtref     gtref;
    method Bit#(1)     interrupt();
    interface AxiStreamMaster#(32)     m_axis_rxd;
    interface AxiStreamMaster#(32)     m_axis_rxs;
    interface AxiethbviMac     mac;
    interface AxiethbviMdio     mdio;
    interface AxiethbviMgt     mgt;
    interface AxiethbviMmcm     mmcm;
    interface AxiethbviPhy     phy;
    interface AxiethbviPma     pma;
    interface AxiethbviRef     reff;
    interface AxiethbviRxuserclk     rxuserclk2;
    interface AxiethbviRxuserclk     rxuserclk;
    interface AxiethbviS_axi     s_axi;
    interface AxiStreamSlave#(32)     s_axis_txc;
    interface AxiStreamSlave#(32)     s_axis_txd;
    interface AxiethbviSgmii     sgmii;
    interface AxiethbviSignal     signal;
    interface AxiethbviUserclk     userclk2;
    interface AxiethbviUserclk     userclk;
endinterface
import "BVI" axi_ethernet_0 =
module mkAxiEthBvi#(Clock s_axi_clk, Reset s_axi_reset)(AxiEthBvi);
    default_clock clk();
    default_reset rst();
    input_clock (s_axi_lite_clk) = s_axi_clk;
    input_reset (s_axi_lite_resetn) = s_axi_reset;
    interface AxiethbviAxi     axi;
        method rxd_arstn(axi_rxd_arstn) enable((*inhigh*) EN_axi_rxd_arstn);
        method rxs_arstn(axi_rxs_arstn) enable((*inhigh*) EN_axi_rxs_arstn);
        method txc_arstn(axi_txc_arstn) enable((*inhigh*) EN_axi_txc_arstn);
        method txd_arstn(axi_txd_arstn) enable((*inhigh*) EN_axi_txd_arstn);
    endinterface
    interface AxiethbviAxis     axis;
        method clk(axis_clk) enable((*inhigh*) EN_axis_clk);
    endinterface
    interface AxiethbviGt     gt0;
        method gt0_qplloutclk_out qplloutclk_out();
        method gt0_qplloutrefclk_out qplloutrefclk_out();
    endinterface
    interface AxiethbviGtref     gtref;
        method gtref_clk_buf_out clk_buf_out();
        method gtref_clk_out clk_out();
    endinterface
    method interrupt interrupt();
    interface AxiStreamMaster     m_axis_rxd;
        method m_axis_rxd_tdata tdata();
        method m_axis_rxd_tkeep tkeep();
        method m_axis_rxd_tlast tlast();
        method tready(m_axis_rxd_tready) enable((*inhigh*) EN_m_axis_rxd_tready);
        method m_axis_rxd_tvalid tvalid();
    endinterface
    interface AxiStreamMaster     m_axis_rxs;
        method m_axis_rxs_tdata tdata();
        method m_axis_rxs_tkeep tkeep();
        method m_axis_rxs_tlast tlast();
        method tready(m_axis_rxs_tready) enable((*inhigh*) EN_m_axis_rxs_tready);
        method m_axis_rxs_tvalid tvalid();
    endinterface
    interface AxiethbviMac     mac;
        method mac_irq irq();
    endinterface
    interface AxiethbviMdio     mdio;
        method mdio_mdc mdc();
        method mdio_i(mdio_mdio_i) enable((*inhigh*) EN_mdio_mdio_i);
        method mdio_mdio_o mdio_o();
        method mdio_mdio_t mdio_t();
    endinterface
    interface AxiethbviMgt     mgt;
        method clk_clk_n(mgt_clk_clk_n) enable((*inhigh*) EN_mgt_clk_clk_n);
        method clk_clk_p(mgt_clk_clk_p) enable((*inhigh*) EN_mgt_clk_clk_p);
    endinterface
    interface AxiethbviMmcm     mmcm;
        method mmcm_locked_out locked_out();
    endinterface
    interface AxiethbviPhy     phy;
        method phy_rst_n rst_n();
    endinterface
    interface AxiethbviPma     pma;
        method pma_reset_out reset_out();
    endinterface
    interface AxiethbviRef     reff;
        method clk(ref_clk) enable((*inhigh*) EN_ref_clk);
    endinterface
    interface AxiethbviRxuserclk     rxuserclk2;
        method rxuserclk2_out out();
    endinterface
    interface AxiethbviRxuserclk     rxuserclk;
        method rxuserclk_out out();
    endinterface
    interface AxiethbviS_axi     s_axi;
        method araddr(s_axi_araddr) enable((*inhigh*) EN_s_axi_araddr) clocked_by (s_axi_clk) reset_by (s_axi_reset);
        method s_axi_arready arready() clocked_by (s_axi_clk) reset_by (s_axi_reset);
        method arvalid(s_axi_arvalid) enable((*inhigh*) EN_s_axi_arvalid) clocked_by (s_axi_clk) reset_by (s_axi_reset);
        method awaddr(s_axi_awaddr) enable((*inhigh*) EN_s_axi_awaddr) clocked_by (s_axi_clk) reset_by (s_axi_reset);
        method s_axi_awready awready() clocked_by (s_axi_clk) reset_by (s_axi_reset);
        method awvalid(s_axi_awvalid) enable((*inhigh*) EN_s_axi_awvalid) clocked_by (s_axi_clk) reset_by (s_axi_reset);
        method bready(s_axi_bready) enable((*inhigh*) EN_s_axi_bready) clocked_by (s_axi_clk) reset_by (s_axi_reset);
        method s_axi_bresp bresp() clocked_by (s_axi_clk) reset_by (s_axi_reset);
        method s_axi_bvalid bvalid() clocked_by (s_axi_clk) reset_by (s_axi_reset);
        method s_axi_rdata rdata() clocked_by (s_axi_clk) reset_by (s_axi_reset);
        method rready(s_axi_rready) enable((*inhigh*) EN_s_axi_rready) clocked_by (s_axi_clk) reset_by (s_axi_reset);
        method s_axi_rresp rresp() clocked_by (s_axi_clk) reset_by (s_axi_reset);
        method s_axi_rvalid rvalid() clocked_by (s_axi_clk) reset_by (s_axi_reset);
        method wdata(s_axi_wdata) enable((*inhigh*) EN_s_axi_wdata) clocked_by (s_axi_clk) reset_by (s_axi_reset);
        method s_axi_wready wready() clocked_by (s_axi_clk) reset_by (s_axi_reset);
        method wstrb(s_axi_wstrb) enable((*inhigh*) EN_s_axi_wstrb) clocked_by (s_axi_clk) reset_by (s_axi_reset);
        method wvalid(s_axi_wvalid) enable((*inhigh*) EN_s_axi_wvalid) clocked_by (s_axi_clk) reset_by (s_axi_reset);
    endinterface
    interface AxiStreamSlave     s_axis_txc;
        method tdata(s_axis_txc_tdata) enable((*inhigh*) EN_s_axis_txc_tdata);
        method tkeep(s_axis_txc_tkeep) enable((*inhigh*) EN_s_axis_txc_tkeep);
        method tlast(s_axis_txc_tlast) enable((*inhigh*) EN_s_axis_txc_tlast);
        method s_axis_txc_tready tready();
        method tvalid(s_axis_txc_tvalid) enable((*inhigh*) EN_s_axis_txc_tvalid);
    endinterface
    interface AxiStreamSlave     s_axis_txd;
        method tdata(s_axis_txd_tdata) enable((*inhigh*) EN_s_axis_txd_tdata);
        method tkeep(s_axis_txd_tkeep) enable((*inhigh*) EN_s_axis_txd_tkeep);
        method tlast(s_axis_txd_tlast) enable((*inhigh*) EN_s_axis_txd_tlast);
        method s_axis_txd_tready tready();
        method tvalid(s_axis_txd_tvalid) enable((*inhigh*) EN_s_axis_txd_tvalid);
    endinterface
    interface AxiethbviSgmii     sgmii;
        method rxn(sgmii_rxn) enable((*inhigh*) EN_sgmii_rxn);
        method rxp(sgmii_rxp) enable((*inhigh*) EN_sgmii_rxp);
        method sgmii_txn txn();
        method sgmii_txp txp();
    endinterface
    interface AxiethbviSignal     signal;
        method detect(signal_detect) enable((*inhigh*) EN_signal_detect);
    endinterface
    interface AxiethbviUserclk     userclk2;
        method userclk2_out out();
    endinterface
    interface AxiethbviUserclk     userclk;
        method userclk_out out();
    endinterface
    schedule (axi.rxd_arstn, axi.rxs_arstn, axi.txc_arstn, axi.txd_arstn, axis.clk, gt0.qplloutclk_out, gt0.qplloutrefclk_out, gtref.clk_buf_out, gtref.clk_out, interrupt, m_axis_rxd.tdata, m_axis_rxd.tkeep, m_axis_rxd.tlast, m_axis_rxd.tready, m_axis_rxd.tvalid, m_axis_rxs.tdata, m_axis_rxs.tkeep, m_axis_rxs.tlast, m_axis_rxs.tready, m_axis_rxs.tvalid, mac.irq, mdio.mdc, mdio.mdio_i, mdio.mdio_o, mdio.mdio_t, mgt.clk_clk_n, mgt.clk_clk_p, mmcm.locked_out, phy.rst_n, pma.reset_out, reff.clk, rxuserclk2.out, rxuserclk.out, s_axi.araddr, s_axi.arready, s_axi.arvalid, s_axi.awaddr, s_axi.awready, s_axi.awvalid, s_axi.bready, s_axi.bresp, s_axi.bvalid, s_axi.rdata, s_axi.rready, s_axi.rresp, s_axi.rvalid, s_axi.wdata, s_axi.wready, s_axi.wstrb, s_axi.wvalid, s_axis_txc.tdata, s_axis_txc.tkeep, s_axis_txc.tlast, s_axis_txc.tready, s_axis_txc.tvalid, s_axis_txd.tdata, s_axis_txd.tkeep, s_axis_txd.tlast, s_axis_txd.tready, s_axis_txd.tvalid, sgmii.rxn, sgmii.rxp, sgmii.txn, sgmii.txp, signal.detect, userclk2.out, userclk.out) CF (axi.rxd_arstn, axi.rxs_arstn, axi.txc_arstn, axi.txd_arstn, axis.clk, gt0.qplloutclk_out, gt0.qplloutrefclk_out, gtref.clk_buf_out, gtref.clk_out, interrupt, m_axis_rxd.tdata, m_axis_rxd.tkeep, m_axis_rxd.tlast, m_axis_rxd.tready, m_axis_rxd.tvalid, m_axis_rxs.tdata, m_axis_rxs.tkeep, m_axis_rxs.tlast, m_axis_rxs.tready, m_axis_rxs.tvalid, mac.irq, mdio.mdc, mdio.mdio_i, mdio.mdio_o, mdio.mdio_t, mgt.clk_clk_n, mgt.clk_clk_p, mmcm.locked_out, phy.rst_n, pma.reset_out, reff.clk, rxuserclk2.out, rxuserclk.out, s_axi.araddr, s_axi.arready, s_axi.arvalid, s_axi.awaddr, s_axi.awready, s_axi.awvalid, s_axi.bready, s_axi.bresp, s_axi.bvalid, s_axi.rdata, s_axi.rready, s_axi.rresp, s_axi.rvalid, s_axi.wdata, s_axi.wready, s_axi.wstrb, s_axi.wvalid, s_axis_txc.tdata, s_axis_txc.tkeep, s_axis_txc.tlast, s_axis_txc.tready, s_axis_txc.tvalid, s_axis_txd.tdata, s_axis_txd.tkeep, s_axis_txd.tlast, s_axis_txd.tready, s_axis_txd.tvalid, sgmii.rxn, sgmii.rxp, sgmii.txn, sgmii.txp, signal.detect, userclk2.out, userclk.out);
endmodule

/*
   ../scripts/importbvi.py
   -o
   AxiEthBvi.bsv
   -P
   AxiEthBvi
   -I
   AxiEthBvi
   ../../out/vc709/axi_ethernet_0/axi_ethernet_0_stub.v
*/

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

(* always_ready, always_enabled *)
interface AxiethbviAxi;
    method Action      rxd_arstn(Bit#(1) v);
    method Action      rxs_arstn(Bit#(1) v);
    method Action      txc_arstn(Bit#(1) v);
    method Action      txd_arstn(Bit#(1) v);
endinterface
(* always_ready, always_enabled *)
interface AxiethbviAxis;
    method Action      clk(Bit#(1) v);
endinterface
(* always_ready, always_enabled *)
interface AxiethbviGt;
    method Bit#(1)     qplloutclk_out();
    method Bit#(1)     qplloutrefclk_out();
endinterface
(* always_ready, always_enabled *)
interface AxiethbviGtref;
    method Bit#(1)     clk_buf_out();
    method Bit#(1)     clk_out();
endinterface
(* always_ready, always_enabled *)
interface AxiethbviMac;
    method Bit#(1)     irq();
endinterface
(* always_ready, always_enabled *)
interface AxiethbviMdio;
    method Bit#(1)     mdc();
    method Action      mdio_i(Bit#(1) v);
    method Bit#(1)     mdio_o();
    method Bit#(1)     mdio_t();
endinterface
(* always_ready, always_enabled *)
interface AxiethbviMgt;
    method Action      clk_clk_n(Bit#(1) v);
    method Action      clk_clk_p(Bit#(1) v);
endinterface
(* always_ready, always_enabled *)
interface AxiethbviMmcm;
    method Bit#(1)     locked_out();
endinterface
(* always_ready, always_enabled *)
interface AxiethbviPhy;
    method Bit#(1)     rst_n();
endinterface
(* always_ready, always_enabled *)
interface AxiethbviPma;
    method Bit#(1)     reset_out();
endinterface
(* always_ready, always_enabled *)
interface AxiethbviRef;
    method Action      clk(Bit#(1) v);
endinterface
(* always_ready, always_enabled *)
interface AxiethbviRxuserclk;
    method Bit#(1)     out();
endinterface
(* always_ready, always_enabled *)
interface AxiethbviS_axi;
    method Action      araddr(Bit#(18) v);
    method Bit#(1)     arready();
    method Action      arvalid(Bit#(1) v);
    method Action      awaddr(Bit#(18) 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 *)
interface AxiethbviS_axi_lite;
    method Action      clk(Bit#(1) v);
    method Action      resetn(Bit#(1) v);
endinterface
(* always_ready, always_enabled *)
interface AxiethbviSgmii;
    method Action      rxn(Bit#(1) v);
    method Action      rxp(Bit#(1) v);
    method Bit#(1)     txn();
    method Bit#(1)     txp();
endinterface
(* always_ready, always_enabled *)
interface AxiethbviSignal;
    method Action      detect(Bit#(1) v);
endinterface
(* always_ready, always_enabled *)
interface AxiethbviUserclk;
    method Bit#(1)     out();
endinterface
(* always_ready, always_enabled *)
interface AxiEthBvi;
    interface AxiethbviAxi     axi;
    interface AxiethbviAxis     axis;
    interface AxiethbviGt     gt0;
    interface AxiethbviGtref     gtref;
    method Bit#(1)     interrupt();
    interface AxiStreamMaster#(32)     m_axis_rxd;
    interface AxiStreamMaster#(32)     m_axis_rxs;
    interface AxiethbviMac     mac;
    interface AxiethbviMdio     mdio;
    interface AxiethbviMgt     mgt;
    interface AxiethbviMmcm     mmcm;
    interface AxiethbviPhy     phy;
    interface AxiethbviPma     pma;
    interface AxiethbviRef     reff;
    interface AxiethbviRxuserclk     rxuserclk2;
    interface AxiethbviRxuserclk     rxuserclk;
    interface AxiethbviS_axi     s_axi;
    interface AxiethbviS_axi_lite     s_axi_lite;
    interface AxiStreamSlave#(32)     s_axis_txc;
    interface AxiStreamSlave#(32)     s_axis_txd;
    interface AxiethbviSgmii     sgmii;
    interface AxiethbviSignal     signal;
    interface AxiethbviUserclk     userclk2;
    interface AxiethbviUserclk     userclk;
endinterface
import "BVI" axi_ethernet_0 =
module mkAxiEthBvi(AxiEthBvi);
    default_clock clk();
    default_reset rst();
    interface AxiethbviAxi     axi;
        method rxd_arstn(axi_rxd_arstn) enable((*inhigh*) EN_axi_rxd_arstn);
        method rxs_arstn(axi_rxs_arstn) enable((*inhigh*) EN_axi_rxs_arstn);
        method txc_arstn(axi_txc_arstn) enable((*inhigh*) EN_axi_txc_arstn);
        method txd_arstn(axi_txd_arstn) enable((*inhigh*) EN_axi_txd_arstn);
    endinterface
    interface AxiethbviAxis     axis;
        method clk(axis_clk) enable((*inhigh*) EN_axis_clk);
    endinterface
    interface AxiethbviGt     gt0;
        method gt0_qplloutclk_out qplloutclk_out();
        method gt0_qplloutrefclk_out qplloutrefclk_out();
    endinterface
    interface AxiethbviGtref     gtref;
        method gtref_clk_buf_out clk_buf_out();
        method gtref_clk_out clk_out();
    endinterface
    method interrupt interrupt();
    interface AxiStreamMaster     m_axis_rxd;
        method m_axis_rxd_tdata tdata();
        method m_axis_rxd_tkeep tkeep();
        method m_axis_rxd_tlast tlast();
        method tready(m_axis_rxd_tready) enable((*inhigh*) EN_m_axis_rxd_tready);
        method m_axis_rxd_tvalid tvalid();
    endinterface
    interface AxiStreamMaster     m_axis_rxs;
        method m_axis_rxs_tdata tdata();
        method m_axis_rxs_tkeep tkeep();
        method m_axis_rxs_tlast tlast();
        method tready(m_axis_rxs_tready) enable((*inhigh*) EN_m_axis_rxs_tready);
        method m_axis_rxs_tvalid tvalid();
    endinterface
    interface AxiethbviMac     mac;
        method mac_irq irq();
    endinterface
    interface AxiethbviMdio     mdio;
        method mdio_mdc mdc();
        method mdio_i(mdio_mdio_i) enable((*inhigh*) EN_mdio_mdio_i);
        method mdio_mdio_o mdio_o();
        method mdio_mdio_t mdio_t();
    endinterface
    interface AxiethbviMgt     mgt;
        method clk_clk_n(mgt_clk_clk_n) enable((*inhigh*) EN_mgt_clk_clk_n);
        method clk_clk_p(mgt_clk_clk_p) enable((*inhigh*) EN_mgt_clk_clk_p);
    endinterface
    interface AxiethbviMmcm     mmcm;
        method mmcm_locked_out locked_out();
    endinterface
    interface AxiethbviPhy     phy;
        method phy_rst_n rst_n();
    endinterface
    interface AxiethbviPma     pma;
        method pma_reset_out reset_out();
    endinterface
    interface AxiethbviRef     reff;
        method clk(ref_clk) enable((*inhigh*) EN_ref_clk);
    endinterface
    interface AxiethbviRxuserclk     rxuserclk2;
        method rxuserclk2_out out();
    endinterface
    interface AxiethbviRxuserclk     rxuserclk;
        method rxuserclk_out out();
    endinterface
    interface AxiethbviS_axi     s_axi;
        method araddr(s_axi_araddr) enable((*inhigh*) EN_s_axi_araddr);
        method s_axi_arready arready();
        method arvalid(s_axi_arvalid) enable((*inhigh*) EN_s_axi_arvalid);
        method awaddr(s_axi_awaddr) enable((*inhigh*) EN_s_axi_awaddr);
        method s_axi_awready awready();
        method awvalid(s_axi_awvalid) enable((*inhigh*) EN_s_axi_awvalid);
        method bready(s_axi_bready) enable((*inhigh*) EN_s_axi_bready);
        method s_axi_bresp bresp();
        method s_axi_bvalid bvalid();
        method s_axi_rdata rdata();
        method rready(s_axi_rready) enable((*inhigh*) EN_s_axi_rready);
        method s_axi_rresp rresp();
        method s_axi_rvalid rvalid();
        method wdata(s_axi_wdata) enable((*inhigh*) EN_s_axi_wdata);
        method s_axi_wready wready();
        method wstrb(s_axi_wstrb) enable((*inhigh*) EN_s_axi_wstrb);
        method wvalid(s_axi_wvalid) enable((*inhigh*) EN_s_axi_wvalid);
    endinterface
    interface AxiethbviS_axi_lite     s_axi_lite;
        method clk(s_axi_lite_clk) enable((*inhigh*) EN_s_axi_lite_clk);
        method resetn(s_axi_lite_resetn) enable((*inhigh*) EN_s_axi_lite_resetn);
    endinterface
    interface AxiStreamSlave     s_axis_txc;
        method tdata(s_axis_txc_tdata) enable((*inhigh*) EN_s_axis_txc_tdata);
        method tkeep(s_axis_txc_tkeep) enable((*inhigh*) EN_s_axis_txc_tkeep);
        method tlast(s_axis_txc_tlast) enable((*inhigh*) EN_s_axis_txc_tlast);
        method s_axis_txc_tready tready();
        method tvalid(s_axis_txc_tvalid) enable((*inhigh*) EN_s_axis_txc_tvalid);
    endinterface
    interface AxiStreamSlave     s_axis_txd;
        method tdata(s_axis_txd_tdata) enable((*inhigh*) EN_s_axis_txd_tdata);
        method tkeep(s_axis_txd_tkeep) enable((*inhigh*) EN_s_axis_txd_tkeep);
        method tlast(s_axis_txd_tlast) enable((*inhigh*) EN_s_axis_txd_tlast);
        method s_axis_txd_tready tready();
        method tvalid(s_axis_txd_tvalid) enable((*inhigh*) EN_s_axis_txd_tvalid);
    endinterface
    interface AxiethbviSgmii     sgmii;
        method rxn(sgmii_rxn) enable((*inhigh*) EN_sgmii_rxn);
        method rxp(sgmii_rxp) enable((*inhigh*) EN_sgmii_rxp);
        method sgmii_txn txn();
        method sgmii_txp txp();
    endinterface
    interface AxiethbviSignal     signal;
        method detect(signal_detect) enable((*inhigh*) EN_signal_detect);
    endinterface
    interface AxiethbviUserclk     userclk2;
        method userclk2_out out();
    endinterface
    interface AxiethbviUserclk     userclk;
        method userclk_out out();
    endinterface
    schedule (axi.rxd_arstn, axi.rxs_arstn, axi.txc_arstn, axi.txd_arstn, axis.clk, gt0.qplloutclk_out, gt0.qplloutrefclk_out, gtref.clk_buf_out, gtref.clk_out, interrupt, m_axis_rxd.tdata, m_axis_rxd.tkeep, m_axis_rxd.tlast, m_axis_rxd.tready, m_axis_rxd.tvalid, m_axis_rxs.tdata, m_axis_rxs.tkeep, m_axis_rxs.tlast, m_axis_rxs.tready, m_axis_rxs.tvalid, mac.irq, mdio.mdc, mdio.mdio_i, mdio.mdio_o, mdio.mdio_t, mgt.clk_clk_n, mgt.clk_clk_p, mmcm.locked_out, phy.rst_n, pma.reset_out, reff.clk, rxuserclk2.out, rxuserclk.out, s_axi.araddr, s_axi.arready, s_axi.arvalid, s_axi.awaddr, s_axi.awready, s_axi.awvalid, s_axi.bready, s_axi.bresp, s_axi.bvalid, s_axi.rdata, s_axi.rready, s_axi.rresp, s_axi.rvalid, s_axi.wdata, s_axi.wready, s_axi.wstrb, s_axi.wvalid, s_axi_lite.clk, s_axi_lite.resetn, s_axis_txc.tdata, s_axis_txc.tkeep, s_axis_txc.tlast, s_axis_txc.tready, s_axis_txc.tvalid, s_axis_txd.tdata, s_axis_txd.tkeep, s_axis_txd.tlast, s_axis_txd.tready, s_axis_txd.tvalid, sgmii.rxn, sgmii.rxp, sgmii.txn, sgmii.txp, signal.detect, userclk2.out, userclk.out) CF (axi.rxd_arstn, axi.rxs_arstn, axi.txc_arstn, axi.txd_arstn, axis.clk, gt0.qplloutclk_out, gt0.qplloutrefclk_out, gtref.clk_buf_out, gtref.clk_out, interrupt, m_axis_rxd.tdata, m_axis_rxd.tkeep, m_axis_rxd.tlast, m_axis_rxd.tready, m_axis_rxd.tvalid, m_axis_rxs.tdata, m_axis_rxs.tkeep, m_axis_rxs.tlast, m_axis_rxs.tready, m_axis_rxs.tvalid, mac.irq, mdio.mdc, mdio.mdio_i, mdio.mdio_o, mdio.mdio_t, mgt.clk_clk_n, mgt.clk_clk_p, mmcm.locked_out, phy.rst_n, pma.reset_out, reff.clk, rxuserclk2.out, rxuserclk.out, s_axi.araddr, s_axi.arready, s_axi.arvalid, s_axi.awaddr, s_axi.awready, s_axi.awvalid, s_axi.bready, s_axi.bresp, s_axi.bvalid, s_axi.rdata, s_axi.rready, s_axi.rresp, s_axi.rvalid, s_axi.wdata, s_axi.wready, s_axi.wstrb, s_axi.wvalid, s_axi_lite.clk, s_axi_lite.resetn, s_axis_txc.tdata, s_axis_txc.tkeep, s_axis_txc.tlast, s_axis_txc.tready, s_axis_txc.tvalid, s_axis_txd.tdata, s_axis_txd.tkeep, s_axis_txd.tlast, s_axis_txd.tready, s_axis_txd.tvalid, sgmii.rxn, sgmii.rxp, sgmii.txn, sgmii.txp, signal.detect, userclk2.out, userclk.out);
endmodule


minor fixes

minor fixes

// Copyright (c) 2014 Cornell University.

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

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

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

package DtpTx;

import FIFO::*;
import FIFOF::*;
import SpecialFIFOs::*;
import Vector::*;
import GetPut::*;
import ClientServer::*;
import FShow::*;
import Probe::*;
import Pipe::*;
import Ethernet::*;

typedef 8  CmdLen;
typedef 32 ParamLen;
typedef 4 GLOBAL_DELAY;
typedef 5 RXTX_DELAY;

typedef struct {
   Bit#(CmdLen)   cmd;
   Bit#(ParamLen) param;
} CmdTup deriving (Eq, Bits, FShow);

typedef struct {
   Bool     mux_sel;
   Bit#(53) c_local;
   Bit#(1)  parity;
} TxStageOneBuf deriving (Eq, Bits);

interface DtpTx;
   interface PipeIn#(Bit#(66))  dtpTxIn;
   interface PipeOut#(Bit#(66)) dtpTxOut;
   interface PipeOut#(Bit#(53)) dtpLocalOut;
   interface PipeIn#(Bit#(53))  dtpGlobalIn;
   interface DtpToPhyIfc api;

   interface PipeIn#(DtpEvent) dtpEventIn;
   interface PipeIn#(Bit#(32)) dtpErrCnt;

   (* always_ready, always_enabled *)
   method Action tx_ready(Bool v);
   (* always_ready, always_enabled *)
   method Action rx_ready(Bool v);
   (* always_ready, always_enabled *)
   method Action switch_mode(Bool v);
   (* always_ready, always_enabled *)
   method Action bsync_lock(Bool v);
endinterface

typedef 3'b100 LOG_TYPE;
typedef 2'b01 INIT_TYPE;
typedef 2'b10 ACK_TYPE;
typedef 2'b11 BEACON_TYPE;

typedef enum {INIT, SENT, SYNC} DtpState
deriving (Bits, Eq);

(* synthesize *)
module mkDtpTxTop(DtpTx);
   DtpTx _a <- mkDtpTx(0, 0);
   return _a;
endmodule

module mkDtpTx#(Integer id, Integer c_local_init)(DtpTx);

   let verbose = True;
   Wire#(Bool) tx_ready_wire <- mkDWire(False);
   Wire#(Bool) rx_ready_wire <- mkDWire(False);
   Wire#(Bool) switch_mode_wire <- mkDWire(False);
   Wire#(Bool) bsync_lock_wire <- mkDWire(False);

   FIFOF#(Bit#(66)) dtpTxInFifo <- mkFIFOF ();

   Reg#(Bool)   is_switch_mode <- mkReg(False); // by default, NIC mode
   Reg#(Bit#(32))  cycle   <- mkReg(0);
   Reg#(DtpState)  curr_state  <- mkReg(INIT);

   Reg#(Bit#(53))  c_local <- mkReg(fromInteger(c_local_init)); //mkReg(0); //fromInteger(c_local_init));
   Reg#(Bit#(53))  c_global <- mkReg(0);
   Reg#(Bit#(53))  delay   <- mkReg(0);
   Reg#(Bit#(32))  timeout_count_init <- mkReg(0);
   Reg#(Bit#(32))  timeout_count_sync <- mkReg(0);
   Reg#(Bit#(64))  jumpCount <- mkReg(0);
   Reg#(Bit#(32))  interval_reg <- mkReg(1000);

   Wire#(Bool) init_rcvd    <- mkDWire(False);
   Wire#(Bool) ack_rcvd     <- mkDWire(False);
   Wire#(Bool) beacon_rcvd  <- mkDWire(False);

   Wire#(Bool) is_idle      <- mkDWire(False);

   Wire#(Bit#(53)) c_local_next <- mkDWire(0);
   FIFOF#(Bit#(2)) txMuxSelFifo <- mkSizedBypassFIFOF(3);

   // Tx Stage 1
   FIFOF#(Bit#(66)) dtpTxInPipelineFifo <- mkFIFOF;
   FIFOF#(Bit#(66)) dtpTxOutFifo <- mkFIFOF;
   FIFOF#(TxStageOneBuf) stageOneFifo <- mkFIFOF;

   FIFOF#(Bit#(53)) initTimestampFifo <- mkBypassFIFOF;
   FIFOF#(Bit#(1)) initParityFifo <- mkBypassFIFOF;
   FIFOF#(Bit#(53)) ackTimestampFifo <- mkBypassFIFOF;

   FIFOF#(Bit#(3))  dtpEventFifo   <- mkFIFOF;
   FIFOF#(Bit#(3))  dtpEventOutputFifo   <- mkFIFOF;
   FIFOF#(Bit#(66)) dtpRxOutFifo <- mkFIFOF;
   FIFOF#(DtpEvent) dtpEventInFifo <- mkFIFOF;
   FIFOF#(Bit#(32)) dtpErrCntFifo <- mkFIFOF;

   FIFOF#(Bit#(53)) dtpLocalOutFifo <- mkFIFOF;
   FIFOF#(Bit#(53)) dtpGlobalInFifo <- mkFIFOF;

   FIFOF#(Bit#(53)) localCompareRemoteFifo  <- mkFIFOF;
   FIFOF#(Bit#(53)) localCompareGlobalFifo  <- mkFIFOF;
   FIFOF#(Bit#(53)) remoteCompareGlobalFifo <- mkFIFOF;
   FIFOF#(Bit#(53)) remoteCompareLocalFifo  <- mkFIFOF;
   FIFOF#(Bit#(53)) globalCompareRemoteFifo <- mkFIFOF;
   FIFOF#(Bit#(53)) globalCompareLocalFifo  <- mkFIFOF;

   FIFOF#(Bit#(53)) localOutputFifo  <- mkFIFOF;
   FIFOF#(Bit#(53)) globalOutputFifo <- mkFIFOF;
   FIFOF#(Bit#(53)) remoteOutputFifo <- mkFIFOF;

   FIFOF#(Bool) localLtRemoteFifo  <- mkFIFOF;
   FIFOF#(Bool) localGeRemoteFifo  <- mkFIFOF;
   FIFOF#(Bool) globalLeRemoteFifo <- mkFIFOF;
   FIFOF#(Bool) globalGtRemoteFifo <- mkFIFOF;
   FIFOF#(Bool) globalLeLocalFifo  <- mkFIFOF;
   FIFOF#(Bool) globalGtLocalFifo  <- mkFIFOF;

   FIFOF#(void) cfFifo <- mkFIFOF;
   FIFOF#(void) dmFifo <- mkFIFOF;

   Reg#(Bool)       log_rcvd     <- mkReg(False);
   FIFOF#(Bit#(53)) fromHostFifo <- mkSizedBypassFIFOF(2);
   FIFOF#(Bit#(53)) toHostFifo   <- mkSizedBypassFIFOF(2);
   FIFOF#(Bit#(32)) delayFifo    <- mkSizedFIFOF(1);
   FIFOF#(Bit#(32)) stateFifo     <- mkSizedFIFOF(1);
   FIFOF#(Bit#(64)) jumpCountFifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(53)) cLocalFifo   <- mkSizedFIFOF(1);
   FIFOF#(Bit#(32)) intervalFifo <- mkSizedFIFOF(1);

//   Wire#(Bit#(53)) dtpGlobal_wires <- mkDWire(0);

   rule cyc;
      cycle <= cycle + 1;
   endrule

   rule set_switch_mode;
      is_switch_mode <= switch_mode_wire; // 0 for NIC, 1 for switch.
   endrule

   // Setup link first if neither Tx or Rx is ready, bypass DTP.
   rule tx_bypass(!tx_ready_wire || !rx_ready_wire || !bsync_lock_wire);
      let v <- toGet(dtpTxInFifo).get;
      dtpTxOutFifo.enq(v);
   endrule

   rule tx_stage1(tx_ready_wire && rx_ready_wire && bsync_lock_wire);
      let v <- toGet(dtpTxInFifo).get();
      Bit#(1) parity;
      Bool    mux_sel;
      Bit#(53) c_local_out;
//      if (is_switch_mode) begin
//          c_local_out = c_global + 2;
//      end
//      else begin
//          c_local_out = c_local + 2;
//      end
      c_local_out = c_local+2; // forward compute parity.
      parity = ^c_local_out[52:0];

      if(v[9:2] == 8'h1e) begin
         mux_sel = True;
         is_idle <= True;
      end
      else begin
         mux_sel = False;
         is_idle <= False;
      end
      //if(verbose) $display("%d: %d dtpTxIn=%h, c_local=%h, is_idle=%h, curr_state=%d", cycle, id, v, c_local, mux_sel, curr_state);
      cfFifo.enq(?);
      dmFifo.enq(?);
      stageOneFifo.enq(TxStageOneBuf{mux_sel: mux_sel,
                                     parity: parity,
                                     c_local: c_local + 1});
      dtpTxInPipelineFifo.enq(v);
   endrule

   Probe#(Bit#(53)) debug_from_host <- mkProbe();
   rule tx_stage2(tx_ready_wire && rx_ready_wire && bsync_lock_wire);
      let val <- toGet(stageOneFifo).get;
      let v <- toGet(dtpTxInPipelineFifo).get();
      let mux_sel = val.mux_sel;
      let c_local = val.c_local;
      let parity = val.parity;

      Bit#(10) block_type;
      Bit#(66) encodeOut;
      Bit#(3) log_type    = fromInteger(valueOf(LOG_TYPE));
      Bit#(2) init_type   = fromInteger(valueOf(INIT_TYPE));
      Bit#(2) ack_type    = fromInteger(valueOf(ACK_TYPE));
      Bit#(2) beacon_type = fromInteger(valueOf(BEACON_TYPE));

      block_type = v[9:0];

      if (mux_sel && fromHostFifo.notEmpty) begin
         let host_data = fromHostFifo.first;
         debug_from_host <= host_data;

         if (host_data[52] == 0) begin
             Bit#(52) tmp;
             if (is_switch_mode) begin
                tmp = c_global[51:0] + 1;
             end
             else begin
                tmp = c_local[51:0] + 1;
             end
//             Bit#(52) tmp = c_local[51:0] + 1;
             encodeOut = {1'b0, tmp, log_type, block_type};
             if(verbose) $display("%d: %d, sending a log message %d", cycle, id, tmp);
         end
         else begin
             encodeOut = {host_data, log_type, block_type};
         end
         fromHostFifo.deq;
      end
      else if (mux_sel && txMuxSelFifo.notEmpty) begin
         let sel = txMuxSelFifo.first;
         if (sel == init_type) begin
            Bit#(53)    tmp = zeroExtend(cycle);
            encodeOut = {tmp+1, parity, init_type, block_type};
            if(verbose) $display("%d: %d, Enqueued outgoing init request %d", cycle, id, tmp+1);
         end
         else if (sel == ack_type) begin
            let init_timestamp <- toGet(initTimestampFifo).get;
            let init_parity <- toGet(initParityFifo).get;
            encodeOut = {init_timestamp, init_parity, ack_type, block_type};
            if(verbose) $display("%d: %d, Enqueued outgoing ack %d", cycle, id, init_timestamp);
         end
         else if (sel == beacon_type) begin
            Bit#(53) tmp;
            if (is_switch_mode) begin
                tmp = c_global + 1;
                parity = ^tmp[52:0];
            end
            else begin
                tmp = c_local+1;
            end
            encodeOut = {tmp, parity, beacon_type, block_type};
            if(verbose) $display("%d: %d, Enqueued outgoing beacon %d", cycle, id, c_local+1);
         end
         else begin
            encodeOut = v; //should never happen
         end
         txMuxSelFifo.deq;
      end
      else begin
         encodeOut = v;
      end
      //if(verbose) $display("%d: %d dtpTxOut=%h, c_local=%h, encodeOut=%h", cycle, id, encodeOut, c_local, encodeOut[12:10]);
      dtpTxOutFifo.enq(encodeOut);
   endrule

   // delay measurement
   rule delay_measurment(curr_state == INIT || curr_state == SENT);
      let init_timeout = interval_reg._read;
      let init_type = fromInteger(valueOf(INIT_TYPE));
      let ack_type = fromInteger(valueOf(ACK_TYPE));
      let rxtx_delay = fromInteger(valueOf(RXTX_DELAY));
      dmFifo.deq;
      // Timeout driven output
      if (init_rcvd) begin
         timeout_count_init <= timeout_count_init + 1;
         if (txMuxSelFifo.notFull) begin
            txMuxSelFifo.enq(ack_type);
         end
         if(verbose) $display("%d: %d, send ack, type %d", cycle, id, ack_type);
      end
      else if (timeout_count_init > init_timeout-1) begin
         if (is_idle) begin
            timeout_count_init <= 0;
            if (txMuxSelFifo.notFull) begin
               txMuxSelFifo.enq(init_type);
            end
            if(verbose) $display("%d: %d, init timed_out %d", cycle, id, timeout_count_init);
         end
         else begin
            timeout_count_init <= timeout_count_init + 1;
         end
      end
      else begin
         timeout_count_init <= timeout_count_init + 1;
      end

      // compute delay
      if (ack_rcvd) begin
         let temp <- toGet(ackTimestampFifo).get;
         Bit#(53) tmp2 = zeroExtend(cycle);
         delay <= (tmp2 - temp - 3) >> 1;
         if(verbose) $display("%d: %d update delay=%d, %d, %d", cycle, id, c_local, temp, (tmp2-temp-3)>>1);
      end
   endrule

   // Beacon
   rule beacon(curr_state == SYNC);
      dmFifo.deq;
      let sync_timeout = interval_reg._read;
      let beacon_type = fromInteger(valueOf(BEACON_TYPE));
      let ack_type = fromInteger(valueOf(ACK_TYPE));
      let rxtx_delay = fromInteger(valueOf(RXTX_DELAY));
      if (timeout_count_sync >= sync_timeout-1) begin
         if (is_idle) begin
            timeout_count_sync <= 0;
         end
         else begin
            timeout_count_sync <= timeout_count_sync + 1;
         end
         if (txMuxSelFifo.notFull) begin
            txMuxSelFifo.enq(beacon_type);
         end
      end
      else if (init_rcvd) begin
         if (txMuxSelFifo.notFull) begin
            txMuxSelFifo.enq(ack_type);
         end
         timeout_count_sync <= timeout_count_sync + 1;
      end
      else begin
         timeout_count_sync <= timeout_count_sync + 1;
      end
   endrule

   // DTP state machine
   rule state_init (curr_state == INIT);
      let init_type = fromInteger(valueOf(INIT_TYPE));
      cfFifo.deq;

      // update states
      if (txMuxSelFifo.notEmpty && is_idle) begin
         if (txMuxSelFifo.first == init_type) begin
            curr_state <= SENT;
         end
      end
      else if (init_rcvd) begin
         curr_state <= INIT;
      end
      else begin
         curr_state <= INIT;
      end
      //if(verbose) $display("%d: %d curr_state=%h", cycle, id, curr_state);
   endrule

   rule state_sent (curr_state == SENT);
      let init_type = fromInteger(valueOf(INIT_TYPE));
      cfFifo.deq;

      // update states
      if (init_rcvd) begin
         curr_state <= SENT;
      end
      else if (ack_rcvd) begin
         curr_state <= SYNC;
      end
      else if (txMuxSelFifo.notEmpty) begin
         if (txMuxSelFifo.first == init_type) begin
            curr_state <= INIT;
         end
      end
      else begin
         curr_state <= SENT;
      end
   endrule

   rule state_sync (curr_state == SYNC);
      cfFifo.deq;

      // update states
      if (init_rcvd) begin
         curr_state <= SYNC;
      end
      else begin
         curr_state <= SYNC;
      end
   endrule

   rule switch_in_c_local(is_switch_mode);
      //if(verbose) $display("%d: send c_local %h to L2", cycle, c_local);
      dtpLocalOutFifo.enq(c_local);
   endrule

   rule switch_out_c_global;
      let v <- toGet(dtpGlobalInFifo).get;
      let global_delay = fromInteger(valueOf(GLOBAL_DELAY));
      c_global <= v + global_delay + 1;
//      dtpGlobal_wires <= v + global_delay;
      if (is_switch_mode && beacon_rcvd) begin
         if (verbose) $display("%d: received global counter %d", cycle, v);
         globalCompareRemoteFifo.enq(v + 1);
         globalCompareLocalFifo.enq(v + 1);
      end
   endrule

   rule rx_stage1(tx_ready_wire && rx_ready_wire);
      let init_type   = fromInteger(valueOf(INIT_TYPE));
      let ack_type    = fromInteger(valueOf(ACK_TYPE));
      let beacon_type = fromInteger(valueOf(BEACON_TYPE));
      let log_type    = fromInteger(valueOf(LOG_TYPE));
      Bool init_rcvd_next   = False;
      Bool ack_rcvd_next    = False;
      Bool beacon_rcvd_next = False;
      Bool log_rcvd_next    = False;
      if (dtpEventInFifo.notEmpty) begin
         let v <- toGet(dtpEventInFifo).get;
         if ((v.e == init_type)) begin
            let parity = ^(v.t);
            if (initTimestampFifo.notFull && initParityFifo.notFull) begin
               initTimestampFifo.enq(v.t);
               initParityFifo.enq(parity);
            end
            if(verbose) $display("%d: %d DtpTx init_rcvd %h %d", cycle, id, v.e, v.t);
            init_rcvd_next = True;
         end
         else if (v.e == ack_type) begin
            ack_rcvd_next = True;
            // append received timestamp to fifo
            if (ackTimestampFifo.notFull)
               ackTimestampFifo.enq(v.t);
            if(verbose) $display("%d: %d DtpTx ack_rcvd %h %d", cycle, id, v.e, v.t);
         end
         else if (v.e == beacon_type) begin
            beacon_rcvd_next = True;
            if(verbose) $display("%d: %d DtpTx beacon_rcvd %h %d %d", cycle, id, v.e, v.t, c_local);
            localCompareRemoteFifo.enq(c_local+1);
            remoteCompareLocalFifo.enq(v.t+1);
            if (is_switch_mode) begin
               localCompareGlobalFifo.enq(c_local+1);
               remoteCompareGlobalFifo.enq(v.t+1);
            end
         end
         else if (v.e == log_type) begin
            log_rcvd_next = True;
            if(verbose) $display("%d: %d DtpTx log_rcvd %h %d", cycle, id, v.e, v.t);
            if (toHostFifo.notFull) begin
               toHostFifo.enq(v.t);
            end
         end
         dtpEventFifo.enq(v.e);
      end
      else begin
         dtpEventFifo.enq(3'b0);
      end
      init_rcvd   <= init_rcvd_next;
      ack_rcvd    <= ack_rcvd_next;
      beacon_rcvd <= beacon_rcvd_next;
      log_rcvd    <= log_rcvd_next;
   endrule

   rule rx_stage2;
      let v_local <- toGet(localCompareRemoteFifo).get();
      let v_remote <- toGet(remoteCompareLocalFifo).get();
      if(verbose) $display("%d: %d, v_local=%d, v_remote=%d, delay=%d", cycle, id, v_local, v_remote, delay);
      if (v_local < v_remote + delay) begin
         localLtRemoteFifo.enq(True);
         localGeRemoteFifo.enq(False);
      end
      else begin
         localLtRemoteFifo.enq(False);
         localGeRemoteFifo.enq(True);
      end
      localOutputFifo.enq(v_local + 1);
      remoteOutputFifo.enq(v_remote + 1);
   endrule

   rule compare_global_remote (is_switch_mode);
      let global_delay = fromInteger(valueOf(GLOBAL_DELAY));
      let v_global <- toGet(globalCompareRemoteFifo).get();
      let v_remote <- toGet(remoteCompareGlobalFifo).get();
      if (v_global + global_delay <= v_remote + delay) begin
         globalLeRemoteFifo.enq(True);
         globalGtRemoteFifo.enq(False);
      end
      else begin
         globalLeRemoteFifo.enq(False);
         globalGtRemoteFifo.enq(True);
      end
      if(verbose) $display("%d: %d, v_global=%d, v_remote=%d", cycle, id, v_global, v_remote);
      globalOutputFifo.enq(v_global + 1);
   endrule

   rule compare_global_local (is_switch_mode);
      let global_delay = fromInteger(valueOf(GLOBAL_DELAY));
      let v_global <- toGet(globalCompareLocalFifo).get();
      let v_local <- toGet(localCompareGlobalFifo).get();
      if (v_global + global_delay <= v_local + 1) begin
         globalLeLocalFifo.enq(True);
         globalGtLocalFifo.enq(False);
      end
      else begin
         globalLeLocalFifo.enq(False);
         globalGtLocalFifo.enq(True);
      end
      if(verbose) $display("%d: %d, v_global=%d, v_local=%d", cycle, id, v_global, v_local);
   endrule

   rule rx_stage2_bypass;
      let v_event <- toGet(dtpEventFifo).get();
      dtpEventOutputFifo.enq(v_event);
   endrule

   rule rx_stage3_nic_mode (!is_switch_mode);
      let vLocal <- toGet(localOutputFifo).get();
      let vRemote <- toGet(remoteOutputFifo).get();
      let useLocal <- toGet(localGeRemoteFifo).get();
      let incrJump <- toGet(localLtRemoteFifo).get();
      if(verbose) $display("%d: %d vLocal=%d", cycle, id, vLocal);
      if(verbose) $display("%d: %d vRemote=%d", cycle, id, vRemote);
      if(verbose) $display("%d: %d delay=%d", cycle, id, delay);
      if (useLocal) begin
         c_local_next <= vLocal + 1;
      end
      else begin
         c_local_next <= vRemote + delay + 1;
      end

      if (incrJump) begin
         jumpCount <= jumpCount + 1;
      end
   endrule

   rule rx_stage3_switch_mode (is_switch_mode);
      let v_local <- toGet(localOutputFifo).get();
      let v_remote <- toGet(remoteOutputFifo).get();
      let v_global <- toGet(globalOutputFifo).get();
      let isGR <- toGet(globalGtRemoteFifo).get();
      let isGL <- toGet(globalGtLocalFifo).get();
      let isLR <- toGet(localGeRemoteFifo).get();
      let isLG <- toGet(globalLeLocalFifo).get();
      let isRG <- toGet(globalLeRemoteFifo).get();
      let isRL <- toGet(localLtRemoteFifo).get();
      let global_delay = fromInteger(valueOf(GLOBAL_DELAY));
      let err = False;
      if(verbose) $display("%d: isGR=%d, isGL=%d, isLR=%d, isLG=%d, isRG=%d, isRL=%d", cycle, isGR, isGL, isLR, isLG, isRG, isRL);
      if (isGR && isGL) begin
         c_local_next <= v_global + global_delay;
//        err = True;
      end
      else if (isLR && isLG) begin
         c_local_next <= v_local + 1;
      end
      else if (isRG && isRL) begin
         c_local_next <= v_remote + delay;
         err = True;
      end
      else begin
         c_local_next <= v_local + 1;
//         err = True;
      end

      if (err) begin
         jumpCount <= jumpCount + 1;
      end

      if(verbose && id==1) $display("%d: jumpCount = %d", cycle, jumpCount);
   endrule

   rule rx_stage3;
      let v <- toGet(dtpEventOutputFifo).get();
      Bit#(2) beacon_type = fromInteger(valueOf(BEACON_TYPE));
      if (!rx_ready_wire) begin
         c_local <= 0;
      end
      else if (v == zeroExtend(beacon_type)) begin
         c_local <= c_local_next;
         if(verbose) $display("%d: %d c_local_next = %d", cycle, id, c_local_next);
      end
      else begin
         c_local <= c_local + 1;
      end
   endrule

   rule export_delay;
      delayFifo.enq(truncate(delay));
   endrule

   rule export_state;
      stateFifo.enq(zeroExtend(pack(curr_state)));
   endrule

   rule export_jumpCount;
      jumpCountFifo.enq(jumpCount);
   endrule

   rule export_c_local;
      cLocalFifo.enq(c_local);
   endrule

   rule import_interval(intervalFifo.notEmpty);
      let interval = intervalFifo.first;
      interval_reg <= interval;
      intervalFifo.deq;
   endrule

   method Action tx_ready(Bool v);
      tx_ready_wire <= v;
   endmethod

   method Action rx_ready(Bool v);
      rx_ready_wire <= v;
   endmethod

   method Action switch_mode(Bool v);
      switch_mode_wire <= v;
   endmethod

   method Action bsync_lock(Bool v);
      bsync_lock_wire <= v;
   endmethod

   interface api = (interface DtpToPhyIfc;
      interface delayOut = toPipeOut(delayFifo);
      interface stateOut = toPipeOut(stateFifo);
      interface jumpCount = toPipeOut(jumpCountFifo);
      interface cLocalOut = toPipeOut(cLocalFifo);
      interface toHost   = toPipeOut(toHostFifo);
      interface fromHost = toPipeIn(fromHostFifo);
      interface interval = toPipeIn(intervalFifo);
      interface dtpErrCnt = toPipeOut(dtpErrCntFifo);
   endinterface);
   interface dtpEventIn = toPipeIn(dtpEventInFifo);
   interface dtpErrCnt = toPipeIn(dtpErrCntFifo);
   interface dtpTxIn = toPipeIn(dtpTxInFifo);
   interface dtpTxOut = toPipeOut(dtpTxOutFifo);
   interface dtpLocalOut = toPipeOut(dtpLocalOutFifo);
   interface dtpGlobalIn = toPipeIn(dtpGlobalInFifo);
endmodule
endpackage

// Copyright (c) 2014 Cornell University.

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

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

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

package DtpTx;

import FIFO::*;
import FIFOF::*;
import SpecialFIFOs::*;
import Vector::*;
import GetPut::*;
import ClientServer::*;
import FShow::*;
import Probe::*;
import Pipe::*;
import Ethernet::*;

typedef 8  CmdLen;
typedef 32 ParamLen;
typedef 4 GLOBAL_DELAY;
typedef 5 RXTX_DELAY;

typedef struct {
   Bit#(CmdLen)   cmd;
   Bit#(ParamLen) param;
} CmdTup deriving (Eq, Bits, FShow);

typedef struct {
   Bool     mux_sel;
   Bit#(53) c_local;
   Bit#(1)  parity;
} TxStageOneBuf deriving (Eq, Bits);

interface DtpTx;
   interface PipeIn#(Bit#(66))  dtpTxIn;
   interface PipeOut#(Bit#(66)) dtpTxOut;
   interface PipeOut#(Bit#(53)) dtpLocalOut;
   interface PipeIn#(Bit#(53))  dtpGlobalIn;
   interface DtpToPhyIfc api;

   interface PipeIn#(DtpEvent) dtpEventIn;
   interface PipeIn#(Bit#(32)) dtpErrCnt;

   (* always_ready, always_enabled *)
   method Action tx_ready(Bool v);
   (* always_ready, always_enabled *)
   method Action rx_ready(Bool v);
   (* always_ready, always_enabled *)
   method Action switch_mode(Bool v);
   (* always_ready, always_enabled *)
   method Action bsync_lock(Bool v);
endinterface

typedef 3'b100 LOG_TYPE;
typedef 2'b01 INIT_TYPE;
typedef 2'b10 ACK_TYPE;
typedef 2'b11 BEACON_TYPE;

typedef enum {INIT, SENT, SYNC} DtpState
deriving (Bits, Eq);

(* synthesize *)
module mkDtpTxTop(DtpTx);
   DtpTx _a <- mkDtpTx(0, 0);
   return _a;
endmodule

module mkDtpTx#(Integer id, Integer c_local_init)(DtpTx);

   let verbose = True;
   Wire#(Bool) tx_ready_wire <- mkDWire(False);
   Wire#(Bool) rx_ready_wire <- mkDWire(False);
   Wire#(Bool) switch_mode_wire <- mkDWire(False);
   Wire#(Bool) bsync_lock_wire <- mkDWire(False);

   FIFOF#(Bit#(66)) dtpTxInFifo <- mkFIFOF ();

   Reg#(Bool)   is_switch_mode <- mkReg(False); // by default, NIC mode
   Reg#(Bit#(32))  cycle   <- mkReg(0);
   Reg#(DtpState)  curr_state  <- mkReg(INIT);

   Reg#(Bit#(53))  c_local <- mkReg(fromInteger(c_local_init)); //mkReg(0); //fromInteger(c_local_init));
   Reg#(Bit#(53))  c_global <- mkReg(0);
   Reg#(Bit#(53))  delay   <- mkReg(0);
   Reg#(Bit#(32))  timeout_count_init <- mkReg(0);
   Reg#(Bit#(32))  timeout_count_sync <- mkReg(0);
   Reg#(Bit#(64))  jumpCount <- mkReg(0);
   Reg#(Bit#(32))  interval_reg <- mkReg(1000);

   Wire#(Bool) init_rcvd    <- mkDWire(False);
   Wire#(Bool) ack_rcvd     <- mkDWire(False);
   Wire#(Bool) beacon_rcvd  <- mkDWire(False);

   Wire#(Bool) is_idle      <- mkDWire(False);

   Wire#(Bit#(53)) c_local_next <- mkDWire(0);
   FIFOF#(Bit#(2)) txMuxSelFifo <- mkSizedBypassFIFOF(3);

   // Tx Stage 1
   FIFOF#(Bit#(66)) dtpTxInPipelineFifo <- mkFIFOF;
   FIFOF#(Bit#(66)) dtpTxOutFifo <- mkFIFOF;
   FIFOF#(TxStageOneBuf) stageOneFifo <- mkFIFOF;

   FIFOF#(Bit#(53)) initTimestampFifo <- mkBypassFIFOF;
   FIFOF#(Bit#(1)) initParityFifo <- mkBypassFIFOF;
   FIFOF#(Bit#(53)) ackTimestampFifo <- mkBypassFIFOF;

   FIFOF#(Bit#(3))  dtpEventFifo   <- mkFIFOF;
   FIFOF#(Bit#(3))  dtpEventOutputFifo   <- mkFIFOF;
   FIFOF#(Bit#(66)) dtpRxOutFifo <- mkFIFOF;
   FIFOF#(DtpEvent) dtpEventInFifo <- mkFIFOF;
   FIFOF#(Bit#(32)) dtpErrCntFifo <- mkFIFOF;

   FIFOF#(Bit#(53)) dtpLocalOutFifo <- mkFIFOF;
   FIFOF#(Bit#(53)) dtpGlobalInFifo <- mkFIFOF;

   FIFOF#(Bit#(53)) localCompareRemoteFifo  <- mkFIFOF;
   FIFOF#(Bit#(53)) localCompareGlobalFifo  <- mkFIFOF;
   FIFOF#(Bit#(53)) remoteCompareGlobalFifo <- mkFIFOF;
   FIFOF#(Bit#(53)) remoteCompareLocalFifo  <- mkFIFOF;
   FIFOF#(Bit#(53)) globalCompareRemoteFifo <- mkFIFOF;
   FIFOF#(Bit#(53)) globalCompareLocalFifo  <- mkFIFOF;

   FIFOF#(Bit#(53)) localOutputFifo  <- mkFIFOF;
   FIFOF#(Bit#(53)) globalOutputFifo <- mkFIFOF;
   FIFOF#(Bit#(53)) remoteOutputFifo <- mkFIFOF;

   FIFOF#(Bool) localLtRemoteFifo  <- mkFIFOF;
   FIFOF#(Bool) localGeRemoteFifo  <- mkFIFOF;
   FIFOF#(Bool) globalLeRemoteFifo <- mkFIFOF;
   FIFOF#(Bool) globalGtRemoteFifo <- mkFIFOF;
   FIFOF#(Bool) globalLeLocalFifo  <- mkFIFOF;
   FIFOF#(Bool) globalGtLocalFifo  <- mkFIFOF;

   FIFOF#(void) cfFifo <- mkFIFOF;
   FIFOF#(void) dmFifo <- mkFIFOF;

   Reg#(Bool)       log_rcvd     <- mkReg(False);
   FIFOF#(Bit#(53)) fromHostFifo <- mkSizedBypassFIFOF(2);
   FIFOF#(Bit#(53)) toHostFifo   <- mkSizedBypassFIFOF(2);
   FIFOF#(Bit#(32)) delayFifo    <- mkSizedFIFOF(1);
   FIFOF#(Bit#(32)) stateFifo     <- mkSizedFIFOF(1);
   FIFOF#(Bit#(64)) jumpCountFifo <- mkSizedFIFOF(1);
   FIFOF#(Bit#(53)) cLocalFifo   <- mkSizedFIFOF(1);
   FIFOF#(Bit#(32)) intervalFifo <- mkSizedFIFOF(1);

//   Wire#(Bit#(53)) dtpGlobal_wires <- mkDWire(0);

   rule cyc;
      cycle <= cycle + 1;
   endrule

   rule set_switch_mode;
      is_switch_mode <= switch_mode_wire; // 0 for NIC, 1 for switch.
   endrule

   // Setup link first if neither Tx or Rx is ready, bypass DTP.
   rule tx_bypass(!tx_ready_wire || !rx_ready_wire || !bsync_lock_wire);
      let v <- toGet(dtpTxInFifo).get;
      dtpTxOutFifo.enq(v);
   endrule

   rule tx_stage1(tx_ready_wire && rx_ready_wire && bsync_lock_wire);
      let v <- toGet(dtpTxInFifo).get();
      Bit#(1) parity;
      Bool    mux_sel;
      Bit#(53) c_local_out;
      if (is_switch_mode) begin
          c_local_out = c_global + 2;
      end
      else begin
          c_local_out = c_local + 2;
      end
      //c_local_out = c_local+2; // forward compute parity.
      parity = ^c_local_out[52:0];

      if(v[9:2] == 8'h1e) begin
         mux_sel = True;
         is_idle <= True;
      end
      else begin
         mux_sel = False;
         is_idle <= False;
      end
      //if(verbose) $display("%d: %d dtpTxIn=%h, c_local=%h, is_idle=%h, curr_state=%d", cycle, id, v, c_local, mux_sel, curr_state);
      cfFifo.enq(?);
      dmFifo.enq(?);
      stageOneFifo.enq(TxStageOneBuf{mux_sel: mux_sel,
                                     parity: parity,
                                     c_local: c_local+1});
      dtpTxInPipelineFifo.enq(v);
   endrule

   Probe#(Bit#(53)) debug_from_host <- mkProbe();
   rule tx_stage2(tx_ready_wire && rx_ready_wire && bsync_lock_wire);
      let val <- toGet(stageOneFifo).get;
      let v <- toGet(dtpTxInPipelineFifo).get();
      let mux_sel = val.mux_sel;
      let c_local = val.c_local;
      let parity = val.parity;

      Bit#(10) block_type;
      Bit#(66) encodeOut;
      Bit#(3) log_type    = fromInteger(valueOf(LOG_TYPE));
      Bit#(2) init_type   = fromInteger(valueOf(INIT_TYPE));
      Bit#(2) ack_type    = fromInteger(valueOf(ACK_TYPE));
      Bit#(2) beacon_type = fromInteger(valueOf(BEACON_TYPE));

      block_type = v[9:0];

      if (mux_sel && fromHostFifo.notEmpty) begin
         let host_data = fromHostFifo.first;
         debug_from_host <= host_data;

         if (host_data[52] == 0) begin
             Bit#(52) tmp = c_local[51:0] + 1;
             encodeOut = {1'b0, tmp, log_type, block_type};
             if(verbose) $display("%d: %d, sending a log message %d", cycle, id, tmp);
         end
         else begin
             encodeOut = {host_data, log_type, block_type};
         end
         fromHostFifo.deq;
      end
      else if (mux_sel && txMuxSelFifo.notEmpty) begin
         let sel = txMuxSelFifo.first;
         if (sel == init_type) begin
            Bit#(53)    tmp = zeroExtend(cycle);
            encodeOut = {tmp+1, parity, init_type, block_type};
            if(verbose) $display("%d: %d, Enqueued outgoing init request %d", cycle, id, tmp+1);
         end
         else if (sel == ack_type) begin
            let init_timestamp <- toGet(initTimestampFifo).get;
            let init_parity <- toGet(initParityFifo).get;
            encodeOut = {init_timestamp, init_parity, ack_type, block_type};
            if(verbose) $display("%d: %d, Enqueued outgoing ack %d", cycle, id, init_timestamp);
         end
         else if (sel == beacon_type) begin
            encodeOut = {c_local+1, parity, beacon_type, block_type};
            if(verbose) $display("%d: %d, Enqueued outgoing beacon %d", cycle, id, c_local+1);
         end
         else begin
            encodeOut = v; //should never happen
         end
         txMuxSelFifo.deq;
      end
      else begin
         encodeOut = v;
      end
      //if(verbose) $display("%d: %d dtpTxOut=%h, c_local=%h, encodeOut=%h", cycle, id, encodeOut, c_local, encodeOut[12:10]);
      dtpTxOutFifo.enq(encodeOut);
   endrule

   // delay measurement
   rule delay_measurment(curr_state == INIT || curr_state == SENT);
      let init_timeout = interval_reg._read;
      let init_type = fromInteger(valueOf(INIT_TYPE));
      let ack_type = fromInteger(valueOf(ACK_TYPE));
      let rxtx_delay = fromInteger(valueOf(RXTX_DELAY));
      dmFifo.deq;
      // Timeout driven output
      if (init_rcvd) begin
         timeout_count_init <= timeout_count_init + 1;
         if (txMuxSelFifo.notFull) begin
            txMuxSelFifo.enq(ack_type);
         end
         if(verbose) $display("%d: %d, send ack, type %d", cycle, id, ack_type);
      end
      else if (timeout_count_init > init_timeout-1) begin
         if (is_idle) begin
            timeout_count_init <= 0;
            if (txMuxSelFifo.notFull) begin
               txMuxSelFifo.enq(init_type);
            end
            if(verbose) $display("%d: %d, init timed_out %d", cycle, id, timeout_count_init);
         end
         else begin
            timeout_count_init <= timeout_count_init + 1;
         end
      end
      else begin
         timeout_count_init <= timeout_count_init + 1;
      end

      // compute delay
      if (ack_rcvd) begin
         let temp <- toGet(ackTimestampFifo).get;
         Bit#(53) tmp2 = zeroExtend(cycle);
         delay <= (tmp2 - temp - 3) >> 1;
         if(verbose) $display("%d: %d update delay=%d, %d, %d", cycle, id, c_local, temp, (tmp2-temp-3)>>1);
      end
   endrule

   // Beacon
   rule beacon(curr_state == SYNC);
      dmFifo.deq;
      let sync_timeout = interval_reg._read;
      let beacon_type = fromInteger(valueOf(BEACON_TYPE));
      let ack_type = fromInteger(valueOf(ACK_TYPE));
      let rxtx_delay = fromInteger(valueOf(RXTX_DELAY));
      if (timeout_count_sync >= sync_timeout-1) begin
         if (is_idle) begin
            timeout_count_sync <= 0;
         end
         else begin
            timeout_count_sync <= timeout_count_sync + 1;
         end
         if (txMuxSelFifo.notFull) begin
            txMuxSelFifo.enq(beacon_type);
         end
      end
      else if (init_rcvd) begin
         if (txMuxSelFifo.notFull) begin
            txMuxSelFifo.enq(ack_type);
         end
         timeout_count_sync <= timeout_count_sync + 1;
      end
      else begin
         timeout_count_sync <= timeout_count_sync + 1;
      end
   endrule

   // DTP state machine
   rule state_init (curr_state == INIT);
      let init_type = fromInteger(valueOf(INIT_TYPE));
      cfFifo.deq;

      // update states
      if (txMuxSelFifo.notEmpty && is_idle) begin
         if (txMuxSelFifo.first == init_type) begin
            curr_state <= SENT;
         end
      end
      else if (init_rcvd) begin
         curr_state <= INIT;
      end
      else begin
         curr_state <= INIT;
      end
      //if(verbose) $display("%d: %d curr_state=%h", cycle, id, curr_state);
   endrule

   rule state_sent (curr_state == SENT);
      let init_type = fromInteger(valueOf(INIT_TYPE));
      cfFifo.deq;

      // update states
      if (init_rcvd) begin
         curr_state <= SENT;
      end
      else if (ack_rcvd) begin
         curr_state <= SYNC;
      end
      else if (txMuxSelFifo.notEmpty) begin
         if (txMuxSelFifo.first == init_type) begin
            curr_state <= INIT;
         end
      end
      else begin
         curr_state <= SENT;
      end
   endrule

   rule state_sync (curr_state == SYNC);
      cfFifo.deq;

      // update states
      if (init_rcvd) begin
         curr_state <= SYNC;
      end
      else begin
         curr_state <= SYNC;
      end
   endrule

   rule switch_in_c_local(is_switch_mode);
      //if(verbose) $display("%d: send c_local %h to L2", cycle, c_local);
      dtpLocalOutFifo.enq(c_local);
   endrule

   rule switch_out_c_global;
      let v <- toGet(dtpGlobalInFifo).get;
      let global_delay = fromInteger(valueOf(GLOBAL_DELAY));
      c_global <= v + global_delay + 1;
//      dtpGlobal_wires <= v + global_delay;
      if (is_switch_mode && beacon_rcvd) begin
         if (verbose) $display("%d: received global counter %d", cycle, v);
         globalCompareRemoteFifo.enq(v + 1);
         globalCompareLocalFifo.enq(v + 1);
      end
   endrule

   rule rx_stage1(tx_ready_wire && rx_ready_wire);
      let init_type   = fromInteger(valueOf(INIT_TYPE));
      let ack_type    = fromInteger(valueOf(ACK_TYPE));
      let beacon_type = fromInteger(valueOf(BEACON_TYPE));
      let log_type    = fromInteger(valueOf(LOG_TYPE));
      Bool init_rcvd_next   = False;
      Bool ack_rcvd_next    = False;
      Bool beacon_rcvd_next = False;
      Bool log_rcvd_next    = False;
      if (dtpEventInFifo.notEmpty) begin
         let v <- toGet(dtpEventInFifo).get;
         if ((v.e == init_type)) begin
            let parity = ^(v.t);
            if (initTimestampFifo.notFull && initParityFifo.notFull) begin
               initTimestampFifo.enq(v.t);
               initParityFifo.enq(parity);
            end
            if(verbose) $display("%d: %d DtpTx init_rcvd %h %d", cycle, id, v.e, v.t);
            init_rcvd_next = True;
         end
         else if (v.e == ack_type) begin
            ack_rcvd_next = True;
            // append received timestamp to fifo
            if (ackTimestampFifo.notFull)
               ackTimestampFifo.enq(v.t);
            if(verbose) $display("%d: %d DtpTx ack_rcvd %h %d", cycle, id, v.e, v.t);
         end
         else if (v.e == beacon_type) begin
            beacon_rcvd_next = True;
            if(verbose) $display("%d: %d DtpTx beacon_rcvd %h %d %d", cycle, id, v.e, v.t, c_local);
            localCompareRemoteFifo.enq(c_local+1);
            remoteCompareLocalFifo.enq(v.t+1);
            if (is_switch_mode) begin
               localCompareGlobalFifo.enq(c_local+1);
               remoteCompareGlobalFifo.enq(v.t+1);
            end
         end
         else if (v.e == log_type) begin
            log_rcvd_next = True;
            if(verbose) $display("%d: %d DtpTx log_rcvd %h %d", cycle, id, v.e, v.t);
            if (toHostFifo.notFull) begin
               toHostFifo.enq(v.t);
            end
         end
         dtpEventFifo.enq(v.e);
      end
      else begin
         dtpEventFifo.enq(3'b0);
      end
      init_rcvd   <= init_rcvd_next;
      ack_rcvd    <= ack_rcvd_next;
      beacon_rcvd <= beacon_rcvd_next;
      log_rcvd    <= log_rcvd_next;
   endrule

   rule rx_stage2;
      let v_local <- toGet(localCompareRemoteFifo).get();
      let v_remote <- toGet(remoteCompareLocalFifo).get();
      if(verbose) $display("%d: %d, v_local=%d, v_remote=%d, delay=%d", cycle, id, v_local, v_remote, delay);
      if (v_local < v_remote + delay) begin
         localLtRemoteFifo.enq(True);
         localGeRemoteFifo.enq(False);
      end
      else begin
         localLtRemoteFifo.enq(False);
         localGeRemoteFifo.enq(True);
      end
      localOutputFifo.enq(v_local + 1);
      remoteOutputFifo.enq(v_remote + 1);
   endrule

   rule compare_global_remote (is_switch_mode);
      let global_delay = fromInteger(valueOf(GLOBAL_DELAY));
      let v_global <- toGet(globalCompareRemoteFifo).get();
      let v_remote <- toGet(remoteCompareGlobalFifo).get();
      if (v_global + global_delay <= v_remote + delay) begin
         globalLeRemoteFifo.enq(True);
         globalGtRemoteFifo.enq(False);
      end
      else begin
         globalLeRemoteFifo.enq(False);
         globalGtRemoteFifo.enq(True);
      end
      if(verbose) $display("%d: %d, v_global=%d, v_remote=%d", cycle, id, v_global, v_remote);
      globalOutputFifo.enq(v_global + 1);
   endrule

   rule compare_global_local (is_switch_mode);
      let global_delay = fromInteger(valueOf(GLOBAL_DELAY));
      let v_global <- toGet(globalCompareLocalFifo).get();
      let v_local <- toGet(localCompareGlobalFifo).get();
      if (v_global + global_delay <= v_local + 1) begin
         globalLeLocalFifo.enq(True);
         globalGtLocalFifo.enq(False);
      end
      else begin
         globalLeLocalFifo.enq(False);
         globalGtLocalFifo.enq(True);
      end
      if(verbose) $display("%d: %d, v_global=%d, v_local=%d", cycle, id, v_global, v_local);
   endrule

   rule rx_stage2_bypass;
      let v_event <- toGet(dtpEventFifo).get();
      dtpEventOutputFifo.enq(v_event);
   endrule

   rule rx_stage3_nic_mode (!is_switch_mode);
      let vLocal <- toGet(localOutputFifo).get();
      let vRemote <- toGet(remoteOutputFifo).get();
      let useLocal <- toGet(localGeRemoteFifo).get();
      let incrJump <- toGet(localLtRemoteFifo).get();
      if(verbose) $display("%d: %d vLocal=%d", cycle, id, vLocal);
      if(verbose) $display("%d: %d vRemote=%d", cycle, id, vRemote);
      if(verbose) $display("%d: %d delay=%d", cycle, id, delay);
      if (useLocal) begin
         c_local_next <= vLocal + 1;
      end
      else begin
         c_local_next <= vRemote + delay + 1;
      end

      if (incrJump) begin
         jumpCount <= jumpCount + 1;
      end
   endrule

   rule rx_stage3_switch_mode (is_switch_mode);
      let v_local <- toGet(localOutputFifo).get();
      let v_remote <- toGet(remoteOutputFifo).get();
      let v_global <- toGet(globalOutputFifo).get();
      let isGR <- toGet(globalGtRemoteFifo).get();
      let isGL <- toGet(globalGtLocalFifo).get();
      let isLR <- toGet(localGeRemoteFifo).get();
      let isLG <- toGet(globalLeLocalFifo).get();
      let isRG <- toGet(globalLeRemoteFifo).get();
      let isRL <- toGet(localLtRemoteFifo).get();
      let global_delay = fromInteger(valueOf(GLOBAL_DELAY));
      let err = False;
      if(verbose) $display("%d: isGR=%d, isGL=%d, isLR=%d, isLG=%d, isRG=%d, isRL=%d", cycle, isGR, isGL, isLR, isLG, isRG, isRL);
      if (isGR && isGL) begin
         c_local_next <= v_global + global_delay;
//        err = True;
      end
      else if (isLR && isLG) begin
         c_local_next <= v_local + 1;
      end
      else if (isRG && isRL) begin
         c_local_next <= v_remote + delay;
         err = True;
      end
      else begin
         c_local_next <= v_local + 1;
//         err = True;
      end

      if (err) begin
         jumpCount <= jumpCount + 1;
      end

      if(verbose && id==1) $display("%d: jumpCount = %d", cycle, jumpCount);
   endrule

   rule rx_stage3;
      let v <- toGet(dtpEventOutputFifo).get();
      Bit#(2) beacon_type = fromInteger(valueOf(BEACON_TYPE));
      if (!rx_ready_wire) begin
         c_local <= 0;
      end
      else if (v == zeroExtend(beacon_type)) begin
         c_local <= c_local_next;
         if(verbose) $display("%d: %d c_local_next = %d", cycle, id, c_local_next);
      end
      else begin
         c_local <= c_local + 1;
      end
   endrule

   rule export_delay;
      delayFifo.enq(truncate(delay));
   endrule

   rule export_state;
      stateFifo.enq(zeroExtend(pack(curr_state)));
   endrule

   rule export_jumpCount;
      jumpCountFifo.enq(jumpCount);
   endrule

   rule export_c_local;
      cLocalFifo.enq(c_local);
   endrule

   rule import_interval(intervalFifo.notEmpty);
      let interval = intervalFifo.first;
      interval_reg <= interval;
      intervalFifo.deq;
   endrule

   method Action tx_ready(Bool v);
      tx_ready_wire <= v;
   endmethod

   method Action rx_ready(Bool v);
      rx_ready_wire <= v;
   endmethod

   method Action switch_mode(Bool v);
      switch_mode_wire <= v;
   endmethod

   method Action bsync_lock(Bool v);
      bsync_lock_wire <= v;
   endmethod

   interface api = (interface DtpToPhyIfc;
      interface delayOut = toPipeOut(delayFifo);
      interface stateOut = toPipeOut(stateFifo);
      interface jumpCount = toPipeOut(jumpCountFifo);
      interface cLocalOut = toPipeOut(cLocalFifo);
      interface toHost   = toPipeOut(toHostFifo);
      interface fromHost = toPipeIn(fromHostFifo);
      interface interval = toPipeIn(intervalFifo);
      interface dtpErrCnt = toPipeOut(dtpErrCntFifo);
   endinterface);
   interface dtpEventIn = toPipeIn(dtpEventInFifo);
   interface dtpErrCnt = toPipeIn(dtpErrCntFifo);
   interface dtpTxIn = toPipeIn(dtpTxInFifo);
   interface dtpTxOut = toPipeOut(dtpTxOutFifo);
   interface dtpLocalOut = toPipeOut(dtpLocalOutFifo);
   interface dtpGlobalIn = toPipeIn(dtpGlobalInFifo);
endmodule
endpackage


simplify bscan

simplify bscan

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

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

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

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

import FIFOF::*;
import Clocks::*;
import BRAM::*;
import BscanE2::*;
import GetPut::*;
import XilinxCells::*;
import SyncBits::*;

// From: http://siliconexposed.blogspot.com/2013/10/soc-framework-part-5.html
// Example usage: http://www.pld.ttu.ee/~vadim/tty/IAY0570/video_pipeline/psram_app/program_rom.v
// Example usage: http://ohm.bu.edu/~dean/G-2TrackerWORKING/uart_test.vhd

interface BscanBram#(type atype, type dtype);
   method atype getAddr();
   method Bit#(1) getSelected();
   method Bit#(8) getWidth();
   interface Clock jtagClock;
   interface Reset jtagReset;
   interface BRAMClient#(atype, dtype) bramClient;
endinterface

module mkBscanBram#(Integer bus, atype addr)(BscanBram#(atype, dtype))
   provisos (Bits#(atype, asz), Bits#(dtype,dsz), Add#(1, a__, dsz)
,Add#(b__, asz, dsz)
);
   let asz = valueOf(asz);
   let dsz = valueOf(dsz);

   Clock defaultClock <- exposeCurrentClock();
   Reset defaultReset <- exposeCurrentReset();
   BscanE2 bscan <- mkBscanE2(bus);
   Clock tck <- mkClockBUFG(clocked_by bscan.tck);
   Reset rst <- mkAsyncReset(2, defaultReset, tck);

   Reg#(Bit#(asz)) addrReg <- mkReg(0);
   Reg#(Bit#(dsz)) fromBram <- mkReg(0);
   Reg#(Bool) selectdelay <- mkReg(False);
   Reg#(Bool) readData <- mkReg(False);

   Reg#(Bit#(dsz)) shiftReg <- mkReg(0, clocked_by tck, reset_by rst);
   Reg#(Bit#(8)) widthReg <- mkReg(0, clocked_by tck, reset_by rst);
   SyncBitIfc#(Bit#(dsz)) tojtag <- mkSyncBits(0, defaultClock, defaultReset, tck, rst);
   SyncBitIfc#(Bit#(dsz)) fromjtag <- mkSyncBits(0, tck, rst, defaultClock, defaultReset);
   SyncBitIfc#(Bool) selected <- mkSyncBits(False, tck, rst, defaultClock, defaultReset);
   SyncPulseIfc startWrite <- mkSyncHandshake(tck, rst, defaultClock);

   rule fromj;
       fromjtag.send(shiftReg);
   endrule

   rule toj;
       tojtag.send(fromBram);
   endrule

   rule tdo;
      bscan.tdo(shiftReg[0]);
   endrule

   rule updater;
       selected.send(bscan.sel() == 1);
   endrule
   rule writed;
       selectdelay <= selected.read();
   endrule

   rule capturer if(bscan.sel() == 1 && bscan.capture() == 1);
       shiftReg <= tojtag.read();
   endrule
   rule sendwrite if(bscan.sel() == 1 && bscan.update() == 1);
       startWrite.send();
   endrule

   rule shiftrule if (bscan.sel() == 1 && bscan.shift() == 1);
       shiftReg <= { bscan.tdi(), shiftReg[dsz-1:1] };
       widthReg <= widthReg + 1;
   endrule
   rule clearwidth if (bscan.sel() == 0);
       widthReg <= 0;
   endrule

   let readValue = startWrite.pulse() || (selected.read() && !selectdelay);
   rule addrRule if (readValue);
       let v = fromInteger(0);  // first time USER1 selected, reset address
       if (startWrite.pulse())
           v = addrReg + 1;
       addrReg <= v;
   endrule
   rule readClear;
       readData <= readValue;
   endrule

   SyncBitIfc#(Bit#(8)) widthSync <- mkSyncBits(0, tck, rst, defaultClock, defaultReset);
   rule syncw;
       widthSync.send(widthReg);
   endrule
   method atype getAddr;
       return unpack(addrReg);
   endmethod
   method Bit#(1) getSelected();
       return pack(selected.read());
   endmethod
   method Bit#(8) getWidth();
       return widthSync.read();
   endmethod

   interface BRAMClient bramClient;
      interface Get request;
	 method ActionValue#(BRAMRequest#(atype,dtype)) get() if (startWrite.pulse() || readData);
            return BRAMRequest {write:!readData, responseOnWrite:False, address:unpack(addrReg), datain:unpack(fromjtag.read())};
	 endmethod
      endinterface
      interface Put response;
	 method Action put(dtype d);
	    fromBram <= pack(d);
	 endmethod
      endinterface
   endinterface
   interface Clock jtagClock = defaultClock;
   interface Reset jtagReset = defaultReset;
endmodule

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

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

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

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

import FIFOF::*;
import Clocks::*;
import BRAM::*;
import BscanE2::*;
import GetPut::*;
import XilinxCells::*;
import SyncBits::*;

// From: http://siliconexposed.blogspot.com/2013/10/soc-framework-part-5.html
// Example usage: http://www.pld.ttu.ee/~vadim/tty/IAY0570/video_pipeline/psram_app/program_rom.v
// Example usage: http://ohm.bu.edu/~dean/G-2TrackerWORKING/uart_test.vhd

interface BscanBram#(type atype, type dtype);
   method atype getAddr();
   method Bit#(1) getSelected();
   method Bit#(8) getWidth();
   interface Clock jtagClock;
   interface Reset jtagReset;
   interface BRAMClient#(atype, dtype) bramClient;
endinterface

module mkBscanBram#(Integer bus, atype addr)(BscanBram#(atype, dtype))
   provisos (Bits#(atype, asz), Bits#(dtype,dsz), Add#(1, a__, dsz)
,Add#(b__, asz, dsz)
);
   let asz = valueOf(asz);
   let dsz = valueOf(dsz);

   Clock defaultClock <- exposeCurrentClock();
   Reset defaultReset <- exposeCurrentReset();
   BscanE2 bscan <- mkBscanE2(bus);
   Clock tck <- mkClockBUFG(clocked_by bscan.tck);
   Reset rst <- mkAsyncReset(2, defaultReset, tck);

   Reg#(Bit#(asz)) addrReg <- mkReg(0);
   Reg#(Bit#(dsz)) fromBram <- mkReg(0);
   Reg#(Bool) selectdelay <- mkReg(False);
   Reg#(Bool) readData <- mkReg(False);

   Reg#(Bit#(dsz)) shiftReg <- mkReg(0, clocked_by tck, reset_by rst);
   Reg#(Bit#(8)) widthReg <- mkReg(0, clocked_by tck, reset_by rst);
   SyncBitIfc#(Bit#(dsz)) tojtag <- mkSyncBits(0, defaultClock, defaultReset, tck, rst);
   SyncBitIfc#(Bit#(dsz)) fromjtag <- mkSyncBits(0, tck, rst, defaultClock, defaultReset);
   SyncBitIfc#(Bool) selected <- mkSyncBits(False, tck, rst, defaultClock, defaultReset);
   SyncPulseIfc startWrite <- mkSyncHandshake(tck, rst, defaultClock);

   rule fromj;
       fromjtag.send(shiftReg);
   endrule

   rule toj;
       tojtag.send(fromBram);
   endrule

   rule tdo;
      bscan.tdo(shiftReg[0]);
   endrule

   rule updater;
       selected.send(bscan.sel() == 1);
   endrule
   rule writed;
       selectdelay <= selected.read();
   endrule

   rule capturer if(bscan.sel() == 1 && bscan.capture() == 1);
       shiftReg <= tojtag.read();
   endrule
   rule sendwrite if(bscan.sel() == 1 && bscan.update() == 1);
       startWrite.send();
   endrule

   rule shiftrule if (bscan.sel() == 1 && bscan.shift() == 1);
       shiftReg <= { bscan.tdi(), shiftReg[dsz-1:1] };
       widthReg <= widthReg + 1;
   endrule
   rule clearwidth if (bscan.sel() == 0);
       widthReg <= 0;
   endrule

   rule clearRule if (selected.read() && !selectdelay);
       addrReg <= fromInteger(0);  // first time USER1 selected, reset address
       readData <= True;
   endrule
   rule updateRule if (startWrite.pulse());
       addrReg <= addrReg + 1;
       readData <= True;
   endrule
   rule readClear if (readData);
       readData <= False;
   endrule

   SyncBitIfc#(Bit#(8)) widthSync <- mkSyncBits(0, tck, rst, defaultClock, defaultReset);
   rule syncw;
       widthSync.send(widthReg);
   endrule
   method atype getAddr;
       return unpack(addrReg);
   endmethod
   method Bit#(1) getSelected();
       return pack(selected.read());
   endmethod
   method Bit#(8) getWidth();
       return widthSync.read();
   endmethod

   interface BRAMClient bramClient;
      interface Get request;
	 method ActionValue#(BRAMRequest#(atype,dtype)) get() if (startWrite.pulse() || readData);
            return BRAMRequest {write:!readData, responseOnWrite:False, address:unpack(addrReg), datain:unpack(fromjtag.read())};
	 endmethod
      endinterface
      interface Put response;
	 method Action put(dtype d);
	    fromBram <= pack(d);
	 endmethod
      endinterface
   endinterface
   interface Clock jtagClock = defaultClock;
   interface Reset jtagReset = defaultReset;
endmodule


Big cache refactoring.

Big cache refactoring.

import ClientServer::*;
import GetPut::*;
import FIFO::*;
import FIFOF::*;
import SpecialFIFOs::*;
import BRAM::*;
import AvalonCommon::*;

//export Cache(..) mkCache;

interface Cache#(numeric type address_width, numeric type inst_width, numeric type data_width);
    method Action clear();
    interface Client#(AvalonRequest#(address_width,32), Bit#(32)) busClient;
    interface Server#(AvalonRequest#(address_width,32), Bit#(32)) instCache;
    interface Server#(AvalonRequest#(address_width,32), Bit#(32)) dataCache;
endinterface

interface SingleCache#(numeric type address_width, numeric type cache_width);
    method Action clear();
    interface Put#(CacheLine#(address_width)) prefetch;
    interface Client#(AvalonRequest#(address_width,32), Bit#(32)) busClient;
    interface Server#(AvalonRequest#(address_width,32), Bit#(32)) thisCache;
endinterface

typedef struct {
    Bit#(address_width) addr;
    Maybe#(Bit#(32)) data;
} CacheLine#(numeric type address_width) deriving (Bits, Eq);

module mkSingleCache(SingleCache#(address_width,cache_width))
                    provisos (Add#(a__, cache_width, address_width),
                              Add#(b__, cache_width, TAdd#(cache_width, 1)));
    BRAM_Configure cfg = defaultValue;
    BRAM2Port#(Bit#(cache_width), CacheLine#(address_width)) cacheLines <- mkBRAM2Server(cfg);
    RWire#(Bit#(cache_width)) portAaddr <- mkRWire;

    Reg#(Bit#(TAdd#(cache_width,1))) resetCounter <- mkReg(0);
    Integer resetLastBit = valueof(cache_width);
    Bool resetState = resetCounter[resetLastBit] == 1'b0;

    FIFOF#(AvalonRequest#(address_width,32)) pendingReq <- mkFIFOF1;
    Bool hasPending = pendingReq.notEmpty;

    FIFO#(Bit#(0)) mainMemReq <- mkBypassFIFO;
    FIFO#(Bit#(32)) dataResponse <- mkBypassFIFO;

    rule doReset(resetState);
        let cacheLine = CacheLine{addr: 0, data: tagged Invalid};
        Bit#(cache_width) address = truncate(resetCounter);
        let req = BRAMRequest{write: True,
                              responseOnWrite: False,
                              address: address,
                              datain: cacheLine};
        cacheLines.portA.request.put(req);
        req.address = address + 1;
        cacheLines.portB.request.put(req);
        resetCounter <= resetCounter + 2;
    endrule

    rule getResponseFromBRAM(!resetState);
        let cacheLine <- cacheLines.portA.response.get;
        let req = pendingReq.first;
        if(req.command == Read)
          begin
            if(cacheLine.addr == req.addr &&& cacheLine.data matches tagged Valid .data)
              begin
                pendingReq.deq;
                dataResponse.enq(data);
              end
            else
              begin
                mainMemReq.enq(?);
              end
          end
        else  // req.command == Write
          begin
            mainMemReq.enq(?);
          end
    endrule

    method Action clear() if (!resetState);
        resetCounter <= 0;
    endmethod

    interface Put prefetch;
        method Action put(CacheLine#(address_width) cacheLine) if (!resetState);
            Bit#(cache_width) address = truncate(cacheLine.addr);
            Bool willConflict = False;
            if(portAaddr.wget matches tagged Valid .x)
                willConflict = x == address;
            if(!willConflict)
              begin
                let bramReq = BRAMRequest{write: True,
                                          responseOnWrite: False,
                                          address: address,
                                          datain: cacheLine};
                cacheLines.portB.request.put(bramReq);
              end
        endmethod
    endinterface

    interface Client busClient;
        interface Get request;
            method ActionValue#(AvalonRequest#(address_width,32)) get();
                let req = pendingReq.first;
                mainMemReq.deq;
                if(req.command == Write)
                    pendingReq.deq;
                return req;
            endmethod
        endinterface
        interface Put response;
            method Action put(Bit#(32) data);
                dataResponse.enq(data);
                pendingReq.deq;
            endmethod
        endinterface
    endinterface

    interface Server thisCache;
        interface Put request;
            method Action put(AvalonRequest#(address_width,32) req) if (!resetState && !hasPending);
                Bit#(cache_width) address = truncate(req.addr);
                portAaddr.wset(address);
                let bramReq = BRAMRequest{write: req.command == Write,
                                          responseOnWrite: True,
                                          address: address,
                                          datain: ?};
                if(req.command == Write)
                    bramReq.datain = CacheLine{addr: req.addr, data: tagged Valid req.data};
                cacheLines.portA.request.put(bramReq);
                pendingReq.enq(req);
            endmethod
        endinterface
        interface Get response = toGet(dataResponse);
    endinterface
endmodule

/*
module mkCache(Cache#(address_width,inst_width,data_width));
    SingleCache#(address_width,inst_width) instSCache <- mkSingleCache;
    SingleCache#(address_width,data_width) dataSCache <- mkSingleCache;

    method Action clear();
        instSCache.clear;
        dataSCache.clear;
    endmethod

    interface Client busClient;
    endinterface

    interface Server instCache = instSCache.thisCache;
    interface Server dataCache = dataSCache.thisCache;
endmodule
*/

import ClientServer::*;
import GetPut::*;
import SpecialFIFOs::*;
import BRAM::*;
import AvalonCommon::*;

`define cacheSize 10

interface Cache#(address_width);
    interface Client#(AvalonRequest#(address_width,32), Bit#(32)) busClient;
    interface Server#(AvalonRequest#(address_width,32), Bit#(32)) instCache;
    interface Server#(AvalonRequest#(address_width,32), Bit#(32)) dataCache;
endinterface

typedef struct {
    Bit#(address_width) addr;
    Maybe#(Bit#(32)) data;
} CacheLine#(address_width) deriving (Bits, Eq);

module mkCache(Cache#(address_width));
    BRAM_Configure cfg = defaultValue;
    BRAM2Port#(Bit#(`cacheSize), CacheLine#(address_width)) instLines <- mkBRAM2Server(cfg);
    BRAM2Port#(Bit#(`cacheSize), CacheLine#(address_width)) dataLines <- mkBRAM2Server(cfg);

    Reg#(Bit#(TAdd#(`cacheSize,1))) resetCounter <- mkReg(0);
    Bool resetState = resetCounter[`cacheSize] == 1'b0;

    FIFO#(Bit#(address_width)) instLineReqs <- mkFIFO;
    FIFO#(Bit#(address_width)) dataLineReqs <- mkFIFO;

    FIFO#(Bit#(32)) instResps <- mkBypassFIFO;
    FIFO#(Bit#(32)) dataResps <- mkBypassFIFO;

    rule doReset(resetState);
        let req = BRAMRequest{write: True,
                              responseOnWrite: False,
                              address: resetCounter,
                              datain: CacheLine{addr: 0,
                                                data: tagged Invalid}};
        instLines.portA.request.put(req);
        dataLines.portA.request.put(req);
        req.address = req.address + 1;
        instLines.portB.request.put(req);
        dataLines.portB.request.put(req);
        resetCounter <= resetCounter + 2;
    endrule

    rule instCacheLineCheck(!resetState);
        let cacheLine <- instLines.portA.response.get;
        let requestedAddr = instLineReqs.first;
        instLineReqs.deq;
        if(cacheLine.addr == requestedAddr &&& cacheLine.data matches tagged Valid .data)
          begin
            instResps.enq(data);
          end
        else
          begin

          end
    endrule

    rule dataCacheLineCheck(!resetState);
        let cacheLine <- dataLines.portA.response.get;
        let requestedAddr = dataLineReqs.first;
        dataLineReqs.deq;
        if(cacheLine.addr == requestedAddr &&& cacheLine.data matches tagged Valid .data)
            dataResps.enq(data);
    endrule

    interface busClient;
        interface Get request;
            method ActionValue#(AvalonRequest#(address_width,32)) get();

            endmethod
        endinterface
        interface Put response;
            method Action put(Bit#(32) data);
            endmethod
        endinterface
    endinterface

    interface instCache;
        interface Put request;
            method Action put(AvalonRequest#(address_width,32) req) if (!resetState);
                if(req.command == Read)
                  begin
                    instLines.portA.request.put(BRAMRequest{write: False,
                                                            responseOnWrite: False,
                                                            address: truncate(req.addr),
                                                            datain: ?});
                    instLineReqs.enq(req.addr);
                  end
                else
                  begin
                    $display("Cache: Error: Trying to write to the instruction cache");
                  end
            endmethod
        endinterface
        interface Get response = toGet(instResps);
    endinterface

    interface dataCache;
        interface Put request;
            method Action put(AvalonRequest#(address_width,32) req) if (!resetState);
                if(req.command == Read)
                  begin
                    dataLines.portA.request.put(BRAMRequest{write: False,
                                                            responseOnWrite: False,
                                                            address: truncate(req.addr),
                                                            datain: ?});
                    dataLineReqs.enq(req.addr);
                  end
                else
                  begin
                    dataLines.portA.request.put(BRAMRequest{write: True,
                                                            responseOnWrite: False,
                                                            address: truncate(req.addr),
                                                            datain: CacheLine{addr: req.addr,
                                                                              data: tagged Valid req.data}});
                  end
            endmethod
        endinterface
        interface Get response = toGet(dataResps);
    endinterface
endmodule