use clkout0 for vc707 derived clock to enable fractional clock period

////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2012  Bluespec, Inc.  ALL RIGHTS RESERVED.
////////////////////////////////////////////////////////////////////////////////
//  Filename      : ConnectalXilinx7PCIE.bsv
//  Description   :
////////////////////////////////////////////////////////////////////////////////
package PcieEndpointX7;

import Clocks            ::*;
import Vector            ::*;
import Connectable       ::*;
import GetPut            ::*;
import Reserved          ::*;
import TieOff            ::*;
import DefaultValue      ::*;
import DReg              ::*;
import Gearbox           ::*;
import FIFO              ::*;
import FIFOF             ::*;
import SpecialFIFOs      ::*;
import ClientServer      ::*;
import Real              ::*;

import ConnectalClocks   ::*;
import ConnectalXilinxCells   ::*;
import XilinxCells       ::*;
import PCIE              ::*;
import PCIEWRAPPER       ::*;
import Bufgctrl           ::*;
import PcieGearbox       :: *;

(* always_ready, always_enabled *)
interface PCIE_X7#(numeric type lanes);
   interface PciewrapPci_exp#(lanes)   pcie;
   interface PciewrapUser#(lanes)      user;
   interface PciewrapFc#(lanes)        fc;
   interface PciewrapTx#(lanes)        tx;
   interface PciewrapS_axis_tx#(lanes) s_axis_tx;
   interface PciewrapM_axis_rx#(lanes) m_axis_rx;
   interface PciewrapRx#(lanes)        rx;
   interface PciewrapCfg#(lanes)       cfg;
   method    Action                    cfg_dsn(Bit#(64) i);
   interface Clock                     pipe_txoutclk_out;
   method    Action                    pipe_mmcm_lock_in(Bit#(1) v);
   method    Bit#(lanes)               pipe_pclk_sel_out();
endinterface

import "BVI" pcie_7x_0 =
module vMkXilinx7PCIExpress#(PCIEParams params, Clock clk_125mhz, Clock pipe_userclk1_in, Clock pclk_in)(PCIE_X7#(lanes))
   provisos( Add#(1, z, lanes));
   let sys_rst_n <- exposeCurrentReset;

   default_clock clk(sys_clk); // 100 MHz refclk
   default_reset rstn(sys_rst_n) = sys_rst_n;
   input_clock clk_125mhz(pipe_dclk_in) = clk_125mhz;
   input_clock clk_oobclk_in(pipe_oobclk_in) = clk_125mhz;
   input_clock pipe_userclk1_in(pipe_userclk1_in) = pipe_userclk1_in;
   input_clock pipe_userclk2_in(pipe_userclk2_in) = pipe_userclk1_in;
   input_clock pclk_in(pipe_pclk_in) = pclk_in;
   input_clock pclk_usrin(pipe_rxusrclk_in) = pclk_in;
   method pipe_mmcm_lock_in(pipe_mmcm_lock_in) enable((*inhigh*)en_pipe_mmcm_lock_in);
   method pipe_pclk_sel_out pipe_pclk_sel_out   clocked_by(pclk_in);

   interface PciewrapPci_exp pcie;
      method                  rxp(pci_exp_rxp) enable((*inhigh*)en0)    reset_by(no_reset);
      method                  rxn(pci_exp_rxn) enable((*inhigh*)en1)    reset_by(no_reset);
      method pci_exp_txp      txp    reset_by(no_reset);
      method pci_exp_txn      txn    reset_by(no_reset);
   endinterface

   interface PciewrapUser     user;
      output_clock            clk_out(user_clk_out);
      output_reset            reset_out(user_reset_out);
      method user_lnk_up      lnk_up   clocked_by(no_clock) reset_by(no_reset); /* semi-static */
      method user_app_rdy     app_rdy   clocked_by(no_clock) reset_by(no_reset);
   endinterface
    interface PciewrapFc     fc;
      method fc_ph            ph   clocked_by(user_clk_out)    reset_by(no_reset);
      method fc_pd            pd   clocked_by(user_clk_out)    reset_by(no_reset);
      method fc_nph           nph   clocked_by(user_clk_out)    reset_by(no_reset);
      method fc_npd           npd   clocked_by(user_clk_out)    reset_by(no_reset);
      method fc_cplh          cplh   clocked_by(user_clk_out)    reset_by(no_reset);
      method fc_cpld          cpld   clocked_by(user_clk_out)    reset_by(no_reset);
      method                  sel(fc_sel)    enable((*inhigh*)en01)   clocked_by(user_clk_out)    reset_by(no_reset);
   endinterface

   interface PciewrapTx     tx;
      method tx_buf_av        buf_av   clocked_by(user_clk_out)    reset_by(no_reset);
      method tx_err_drop      err_drop   clocked_by(user_clk_out)    reset_by(no_reset);
      method tx_cfg_req       cfg_req   clocked_by(user_clk_out)    reset_by(no_reset);
      method                  cfg_gnt(tx_cfg_gnt)    enable((*inhigh*)en07)   clocked_by(user_clk_out)    reset_by(no_reset);
   endinterface

    interface PciewrapS_axis_tx     s_axis_tx;
      method                  tlast(s_axis_tx_tlast)    enable((*inhigh*)en02)   clocked_by(user_clk_out)    reset_by(no_reset);
      method                  tdata(s_axis_tx_tdata)    enable((*inhigh*)en03)   clocked_by(user_clk_out)    reset_by(no_reset);
      method                  tkeep(s_axis_tx_tkeep)    enable((*inhigh*)en04)   clocked_by(user_clk_out)    reset_by(no_reset);
      method                  tvalid(s_axis_tx_tvalid)    enable((*inhigh*)en05)   clocked_by(user_clk_out)    reset_by(no_reset);
      method                  tuser(s_axis_tx_tuser)    enable((*inhigh*)en06)   clocked_by(user_clk_out)    reset_by(no_reset);
      method s_axis_tx_tready tready   clocked_by(user_clk_out)    reset_by(no_reset);
   endinterface

    interface PciewrapM_axis_rx     m_axis_rx;
      method m_axis_rx_tlast  tlast   clocked_by(user_clk_out)    reset_by(no_reset);
      method m_axis_rx_tdata  tdata   clocked_by(user_clk_out)    reset_by(no_reset);
      method m_axis_rx_tkeep  tkeep   clocked_by(user_clk_out)    reset_by(no_reset);
      method m_axis_rx_tuser  tuser   clocked_by(user_clk_out)    reset_by(no_reset);
      method m_axis_rx_tvalid tvalid   clocked_by(user_clk_out)    reset_by(no_reset);
      method                  tready(m_axis_rx_tready)    enable((*inhigh*)en08)   clocked_by(user_clk_out)    reset_by(no_reset);
   endinterface
   interface PciewrapRx     rx;
      method                  np_ok(rx_np_ok)    enable((*inhigh*)en09)   clocked_by(user_clk_out)    reset_by(no_reset);
      method                  np_req(rx_np_req)    enable((*inhigh*)en10)   clocked_by(user_clk_out)    reset_by(no_reset);
   endinterface

   method                    cfg_dsn(cfg_dsn)    enable((*inhigh*)en25)   clocked_by(user_clk_out);

   interface PciewrapCfg     cfg;
      method cfg_bus_number      bus_number   clocked_by(no_clock) reset_by(no_reset);
      method cfg_device_number   device_number   clocked_by(no_clock) reset_by(no_reset);
      method cfg_function_number function_number   clocked_by(no_clock) reset_by(no_reset);
      method cfg_lcommand        lcommand   clocked_by(user_clk_out) reset_by(no_reset);
      method                     interrupt(cfg_interrupt)    enable((*inhigh*)en32)   clocked_by(user_clk_out) reset_by(no_reset);

      method cfg_bridge_serr_en bridge_serr_en();
      method cfg_command command();
      method cfg_dcommand dcommand();
      method cfg_dcommand2 dcommand2();
      method cfg_lstatus lstatus();
      method cfg_pcie_link_state pcie_link_state();
      method pciecap_interrupt_msgnum(cfg_pciecap_interrupt_msgnum) enable((*inhigh*) EN_cfg_pciecap_interrupt_msgnum);
      method cfg_received_func_lvl_rst received_func_lvl_rst();
      method cfg_slot_control_electromech_il_ctl_pulse slot_control_electromech_il_ctl_pulse();
      method cfg_status status();
      method cfg_to_turnoff to_turnoff();
      method trn_pending(cfg_trn_pending) enable((*inhigh*) EN_cfg_trn_pending);
      method turnoff_ok(cfg_turnoff_ok) enable((*inhigh*) EN_cfg_turnoff_ok);
      method cfg_vc_tcvc_map vc_tcvc_map();
   endinterface

   output_clock pipe_txoutclk_out(pipe_txoutclk_out);

   schedule (user_lnk_up, user_app_rdy, fc_ph, fc_pd, fc_nph, fc_npd, fc_cplh, fc_cpld, fc_sel, s_axis_tx_tlast,
	     s_axis_tx_tdata, s_axis_tx_tkeep, s_axis_tx_tvalid, s_axis_tx_tready, s_axis_tx_tuser, tx_buf_av, tx_err_drop,
	     tx_cfg_req, tx_cfg_gnt, m_axis_rx_tlast, m_axis_rx_tdata, m_axis_rx_tkeep, m_axis_rx_tuser, m_axis_rx_tvalid,
	     m_axis_rx_tready, rx_np_ok, rx_np_req,
	     cfg_bus_number, cfg_device_number, cfg_function_number, cfg_lcommand,
cfg_command, cfg_dcommand, cfg_dcommand2, cfg_lstatus, cfg_pcie_link_state, cfg_received_func_lvl_rst, cfg_status, cfg_to_turnoff, cfg_vc_tcvc_map,
cfg_bridge_serr_en, cfg_slot_control_electromech_il_ctl_pulse,
cfg_pciecap_interrupt_msgnum, cfg_trn_pending, cfg_turnoff_ok,
cfg_interrupt, cfg_dsn,
	     pcie_txp, pcie_txn, pcie_rxp, pcie_rxn, pipe_mmcm_lock_in, pipe_pclk_sel_out
	     ) CF
            (user_lnk_up, user_app_rdy, fc_ph, fc_pd, fc_nph, fc_npd, fc_cplh, fc_cpld, fc_sel, s_axis_tx_tlast,
	     s_axis_tx_tdata, s_axis_tx_tkeep, s_axis_tx_tvalid, s_axis_tx_tready, s_axis_tx_tuser, tx_buf_av, tx_err_drop,
	     tx_cfg_req, tx_cfg_gnt, m_axis_rx_tlast, m_axis_rx_tdata, m_axis_rx_tkeep, m_axis_rx_tuser, m_axis_rx_tvalid,
	     m_axis_rx_tready, rx_np_ok, rx_np_req,
	     cfg_bus_number, cfg_device_number, cfg_function_number, cfg_lcommand,
cfg_command, cfg_dcommand, cfg_dcommand2, cfg_lstatus, cfg_pcie_link_state, cfg_received_func_lvl_rst, cfg_status, cfg_to_turnoff, cfg_vc_tcvc_map,
cfg_bridge_serr_en, cfg_slot_control_electromech_il_ctl_pulse,
cfg_pciecap_interrupt_msgnum, cfg_trn_pending, cfg_turnoff_ok,
cfg_interrupt, cfg_dsn,
	     pcie_txp, pcie_txn, pcie_rxp, pcie_rxn, pipe_mmcm_lock_in, pipe_pclk_sel_out
             );

endmodule: vMkXilinx7PCIExpress

////////////////////////////////////////////////////////////////////////////////
/// Interfaces
////////////////////////////////////////////////////////////////////////////////

interface PcieEndpointX7#(numeric type lanes);
   interface PciewrapPci_exp#(lanes)   pcie;
   interface PciewrapUser#(lanes)      user;
   interface PciewrapCfg#(lanes)       cfg;
   interface Server#(TLPData#(16), TLPData#(16)) tlp;
   interface Clock epClock125;
   interface Reset epReset125;
   interface Clock epClock250;
   interface Reset epReset250;
   interface Clock epPcieClock;
   interface Reset epPcieReset;
   interface Clock epPortalClock;
   interface Reset epPortalReset;
   interface Clock epDerivedClock;
   interface Reset epDerivedReset;
endinterface

typedef struct {
   Bit#(22)      user;
   Bit#(1)       last;
   Bit#(8)       keep;
   Bit#(64)      data;
} AxiRx deriving (Bits, Eq);

typedef struct {
   Bit#(1)       last;
   Bit#(8)       keep;
   Bit#(64)      data;
} AxiTx deriving (Bits, Eq);

`ifdef Artix7
typedef 4 PcieLanes;
`endif
`ifdef BOARD_zc706
typedef 4 PcieLanes;
`endif
`ifdef BOARD_vc707
typedef 8 PcieLanes;
`endif
`ifdef BOARD_kc705
typedef 8 PcieLanes;
`endif
`ifdef BOARD_kc160
typedef 8 PcieLanes;
`endif
`ifdef BOARD_nfsume
typedef 8 PcieLanes;
`endif

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

   PCIEParams params = defaultValue;

   ////////////////////////////////////////////////////////////////////////////////
   /// Design Elements
   ////////////////////////////////////////////////////////////////////////////////
   B2C1 b2c <- mkB2C1();
   ClockGenerator7AdvParams   clockParams = defaultValue;
   clockParams.bandwidth          = "OPTIMIZED";
   clockParams.compensation       = "INTERNAL";
   clockParams.clkfbout_mult_f    = 10.000;
   clockParams.clkfbout_phase     = 0.0;
   clockParams.clkin1_period      = 10.000;
   clockParams.clkout0_divide_f   = 8.000;
   clockParams.clkout0_duty_cycle = 0.5;
   clockParams.clkout0_phase      = 0.0000;
   clockParams.clkout1_divide     = 4;
   clockParams.clkout1_duty_cycle = 0.5;
   clockParams.clkout1_phase      = 0.0000;
   clockParams.clkout2_divide     = 4;
   clockParams.clkout2_duty_cycle = 0.5;
   clockParams.clkout2_phase      = 0.0000;
   clockParams.divclk_divide      = 1;
   clockParams.ref_jitter1        = 0.010;
   clockParams.clkin_buffer = False;
   XClockGenerator7   clockGen <- mkClockGenerator7Adv(clockParams, clocked_by b2c.c);
   C2B c2b_fb <- mkC2B(clockGen.clkfbout, clocked_by clockGen.clkfbout);
   rule txoutrule5;
      clockGen.clkfbin(c2b_fb.o());
   endrule

   Reset defaultReset <- exposeCurrentReset();
   Bufgctrl bbufc <- mkBufgctrl(clockGen.clkout0, defaultReset, clockGen.clkout1, defaultReset);
   Reset rsto <- mkAsyncReset(2, defaultReset, bbufc.o);
   Reg#(Bit#(1)) pclk_sel <- mkReg(0, clocked_by bbufc.o, reset_by rsto);
   Reg#(Bit#(PcieLanes)) pclk_sel_reg1 <- mkReg(0, clocked_by bbufc.o, reset_by rsto);
   Reg#(Bit#(PcieLanes)) pclk_sel_reg2 <- mkReg(0, clocked_by bbufc.o, reset_by rsto);

   rule bufcruleinit;
      bbufc.ce0(1);
      bbufc.ce1(1);
      bbufc.ignore0(0);
      bbufc.ignore1(0);
   endrule
   rule bufcrule;
      bbufc.s0(~pclk_sel);
      bbufc.s1(pclk_sel);
   endrule

   PCIE_X7#(PcieLanes) pcie_ep <- vMkXilinx7PCIExpress(params, clockGen.clkout0, clockGen.clkout2, bbufc.o);
   //new PcieWrap#(PcieLanes)  pciew <- mkPcieWrap();

   FIFOF#(AxiTx)             fAxiTx              <- mkBypassFIFOF(clocked_by pcie_ep.user.clk_out, reset_by noReset);
   FIFOF#(AxiRx)             fAxiRx              <- mkBypassFIFOF(clocked_by pcie_ep.user.clk_out, reset_by noReset);

   (* fire_when_enabled, no_implicit_conditions *)
   rule every1;
      pcie_ep.fc.sel(0 /*RECEIVE_BUFFER_AVAILABLE_SPACE*/);
      pcie_ep.cfg_dsn({ 32'h0000_0001, {{ 8'h1 } , 24'h000A35 }});
      pcie_ep.rx.np_ok(1);
      pcie_ep.rx.np_req(1);
      pcie_ep.tx.cfg_gnt(1);
      pcie_ep.s_axis_tx.tuser(4'b0);
      pcie_ep.m_axis_rx.tready(pack(fAxiRx.notFull));
   endrule
   rule every2;
      pcie_ep.pipe_mmcm_lock_in(pack(clockGen.locked));
   endrule
   rule every3;
      pclk_sel_reg1 <= pcie_ep.pipe_pclk_sel_out();
   endrule

   Clock txoutclk_buf <- mkClockBUFG(clocked_by pcie_ep.pipe_txoutclk_out);

   C2B c2b <- mkC2B(txoutclk_buf);
   rule txoutrule;
      b2c.inputclock(c2b.o());
   endrule

   rule update_psel;
       let ps = pclk_sel;
       pclk_sel_reg2 <= pclk_sel_reg1;
       if ((~pclk_sel_reg2) == 0)
           ps = 1;
       else if (pclk_sel_reg2 == 0)
           ps = 0;
       pclk_sel <= ps;
   endrule

   let txready = (pcie_ep.s_axis_tx.tready != 0 && fAxiTx.notEmpty);

   //(* fire_when_enabled, no_implicit_conditions *)
   rule drive_axi_tx if (txready);
      let info = fAxiTx.first; fAxiTx.deq;
      pcie_ep.s_axis_tx.tvalid(1);
      pcie_ep.s_axis_tx.tlast(info.last);
      pcie_ep.s_axis_tx.tdata(info.data);
      pcie_ep.s_axis_tx.tkeep(info.keep);
   endrule

   (* fire_when_enabled, no_implicit_conditions *)
   rule drive_axi_tx2 if (!txready);
      pcie_ep.s_axis_tx.tvalid(0);
      pcie_ep.s_axis_tx.tlast(0);
      pcie_ep.s_axis_tx.tdata(0);
      pcie_ep.s_axis_tx.tkeep(0);
   endrule

   (* fire_when_enabled *)
   rule sink_axi_rx if (pcie_ep.m_axis_rx.tvalid != 0);
      fAxiRx.enq(AxiRx {user: pcie_ep.m_axis_rx.tuser,
                        last: pcie_ep.m_axis_rx.tlast,
                        keep: pcie_ep.m_axis_rx.tkeep,
                        data: pcie_ep.m_axis_rx.tdata });
   endrule

   // The PCIe endpoint exports full (250MHz) and half-speed (125MHz) clocks
   Clock clock250 = pcie_ep.user.clk_out;
   Reset user_reset_n <- mkResetInverter(pcie_ep.user.reset_out, clocked_by clock250);
   Reset reset250 <- mkAsyncReset(4, user_reset_n, clock250);

   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     = 8; //  125MHz;
   clkgenParams.clkout1_duty_cycle = 0.5;
   clkgenParams.clkout1_phase      = 0.0000;
   ClockGenerator7           clkgen <- mkClockGenerator7(clkgenParams, clocked_by clock250, reset_by user_reset_n);
   Clock clock125 = clkgen.clkout1; /* 125MHz user_clk */
   Reset reset125 <- mkAsyncReset(4, user_reset_n, clock125);
   Clock derivedClock = clkgen.clkout0;
   Reset derivedReset <- mkAsyncReset(4, user_reset_n, derivedClock);

   Server#(TLPData#(8), TLPData#(8)) tlp8 = (interface Server;
						interface Put request;
						   method Action put(TLPData#(8) data);
						      fAxiTx.enq(AxiTx {last: pack(data.eof),
									keep: dwordSwap64BE(data.be), data: dwordSwap64(data.data) });
						   endmethod
						endinterface
						interface Get response;
						   method ActionValue#(TLPData#(8)) get();
						      let info <- toGet(fAxiRx).get;
						      TLPData#(8) retval = defaultValue;
						      retval.sof  = (info.user[14] == 1);
						      retval.eof  = info.last != 0;
						      retval.hit  = info.user[8:2];
						      retval.be= dwordSwap64BE(info.keep);
						      retval.data = dwordSwap64(info.data);
						      return retval;
						   endmethod
						endinterface
					     endinterface);

`ifdef PCIE_250MHZ
   Clock portalClock = clock250;
   Reset portalReset = reset250;
`else
   Clock portalClock = clock125;
   Reset portalReset = reset125;
`endif
   // The PCIE endpoint is processing TLPData#(8)s at 250MHz.  The
   // AXI bridge is accepting TLPData#(16)s at 125 MHz. The
   // connection between the endpoint and the AXI contains GearBox
   // instances for the TLPData#(8)@250 <--> TLPData#(16)@125
   // conversion.
   PcieGearbox gb <- mkPcieGearbox(clock250, reset250, portalClock, portalReset);
   mkConnection(tlp8, gb.tlp, clocked_by portalClock, reset_by portalReset);

   interface tlp = gb.pci;
   interface pcie    = pcie_ep.pcie;
   interface PciewrapUser user = pcie_ep.user;
   interface PciewrapCfg cfg = pcie_ep.cfg;
   interface Clock epClock125 = clock125;
   interface Reset epReset125 = reset125;
   interface Clock epClock250 = clock250;
   interface Reset epReset250 = reset250;
   interface Clock epPcieClock = clock125;
   interface Reset epPcieReset = reset125;
   interface Clock epPortalClock = portalClock;
   interface Reset epPortalReset = portalReset;
   interface Clock epDerivedClock = derivedClock;
   interface Reset epDerivedReset = derivedReset;
endmodule: mkPcieEndpointX7

endpackage: PcieEndpointX7

////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2012  Bluespec, Inc.  ALL RIGHTS RESERVED.
////////////////////////////////////////////////////////////////////////////////
//  Filename      : ConnectalXilinx7PCIE.bsv
//  Description   :
////////////////////////////////////////////////////////////////////////////////
package PcieEndpointX7;

import Clocks            ::*;
import Vector            ::*;
import Connectable       ::*;
import GetPut            ::*;
import Reserved          ::*;
import TieOff            ::*;
import DefaultValue      ::*;
import DReg              ::*;
import Gearbox           ::*;
import FIFO              ::*;
import FIFOF             ::*;
import SpecialFIFOs      ::*;
import ClientServer      ::*;
import Real              ::*;

import ConnectalClocks   ::*;
import ConnectalXilinxCells   ::*;
import XilinxCells       ::*;
import PCIE              ::*;
import PCIEWRAPPER       ::*;
import Bufgctrl           ::*;
import PcieGearbox       :: *;

(* always_ready, always_enabled *)
interface PCIE_X7#(numeric type lanes);
   interface PciewrapPci_exp#(lanes)   pcie;
   interface PciewrapUser#(lanes)      user;
   interface PciewrapFc#(lanes)        fc;
   interface PciewrapTx#(lanes)        tx;
   interface PciewrapS_axis_tx#(lanes) s_axis_tx;
   interface PciewrapM_axis_rx#(lanes) m_axis_rx;
   interface PciewrapRx#(lanes)        rx;
   interface PciewrapCfg#(lanes)       cfg;
   method    Action                    cfg_dsn(Bit#(64) i);
   interface Clock                     pipe_txoutclk_out;
   method    Action                    pipe_mmcm_lock_in(Bit#(1) v);
   method    Bit#(lanes)               pipe_pclk_sel_out();
endinterface

import "BVI" pcie_7x_0 =
module vMkXilinx7PCIExpress#(PCIEParams params, Clock clk_125mhz, Clock pipe_userclk1_in, Clock pclk_in)(PCIE_X7#(lanes))
   provisos( Add#(1, z, lanes));
   let sys_rst_n <- exposeCurrentReset;

   default_clock clk(sys_clk); // 100 MHz refclk
   default_reset rstn(sys_rst_n) = sys_rst_n;
   input_clock clk_125mhz(pipe_dclk_in) = clk_125mhz;
   input_clock clk_oobclk_in(pipe_oobclk_in) = clk_125mhz;
   input_clock pipe_userclk1_in(pipe_userclk1_in) = pipe_userclk1_in;
   input_clock pipe_userclk2_in(pipe_userclk2_in) = pipe_userclk1_in;
   input_clock pclk_in(pipe_pclk_in) = pclk_in;
   input_clock pclk_usrin(pipe_rxusrclk_in) = pclk_in;
   method pipe_mmcm_lock_in(pipe_mmcm_lock_in) enable((*inhigh*)en_pipe_mmcm_lock_in);
   method pipe_pclk_sel_out pipe_pclk_sel_out   clocked_by(pclk_in);

   interface PciewrapPci_exp pcie;
      method                  rxp(pci_exp_rxp) enable((*inhigh*)en0)    reset_by(no_reset);
      method                  rxn(pci_exp_rxn) enable((*inhigh*)en1)    reset_by(no_reset);
      method pci_exp_txp      txp    reset_by(no_reset);
      method pci_exp_txn      txn    reset_by(no_reset);
   endinterface

   interface PciewrapUser     user;
      output_clock            clk_out(user_clk_out);
      output_reset            reset_out(user_reset_out);
      method user_lnk_up      lnk_up   clocked_by(no_clock) reset_by(no_reset); /* semi-static */
      method user_app_rdy     app_rdy   clocked_by(no_clock) reset_by(no_reset);
   endinterface
    interface PciewrapFc     fc;
      method fc_ph            ph   clocked_by(user_clk_out)    reset_by(no_reset);
      method fc_pd            pd   clocked_by(user_clk_out)    reset_by(no_reset);
      method fc_nph           nph   clocked_by(user_clk_out)    reset_by(no_reset);
      method fc_npd           npd   clocked_by(user_clk_out)    reset_by(no_reset);
      method fc_cplh          cplh   clocked_by(user_clk_out)    reset_by(no_reset);
      method fc_cpld          cpld   clocked_by(user_clk_out)    reset_by(no_reset);
      method                  sel(fc_sel)    enable((*inhigh*)en01)   clocked_by(user_clk_out)    reset_by(no_reset);
   endinterface

   interface PciewrapTx     tx;
      method tx_buf_av        buf_av   clocked_by(user_clk_out)    reset_by(no_reset);
      method tx_err_drop      err_drop   clocked_by(user_clk_out)    reset_by(no_reset);
      method tx_cfg_req       cfg_req   clocked_by(user_clk_out)    reset_by(no_reset);
      method                  cfg_gnt(tx_cfg_gnt)    enable((*inhigh*)en07)   clocked_by(user_clk_out)    reset_by(no_reset);
   endinterface

    interface PciewrapS_axis_tx     s_axis_tx;
      method                  tlast(s_axis_tx_tlast)    enable((*inhigh*)en02)   clocked_by(user_clk_out)    reset_by(no_reset);
      method                  tdata(s_axis_tx_tdata)    enable((*inhigh*)en03)   clocked_by(user_clk_out)    reset_by(no_reset);
      method                  tkeep(s_axis_tx_tkeep)    enable((*inhigh*)en04)   clocked_by(user_clk_out)    reset_by(no_reset);
      method                  tvalid(s_axis_tx_tvalid)    enable((*inhigh*)en05)   clocked_by(user_clk_out)    reset_by(no_reset);
      method                  tuser(s_axis_tx_tuser)    enable((*inhigh*)en06)   clocked_by(user_clk_out)    reset_by(no_reset);
      method s_axis_tx_tready tready   clocked_by(user_clk_out)    reset_by(no_reset);
   endinterface

    interface PciewrapM_axis_rx     m_axis_rx;
      method m_axis_rx_tlast  tlast   clocked_by(user_clk_out)    reset_by(no_reset);
      method m_axis_rx_tdata  tdata   clocked_by(user_clk_out)    reset_by(no_reset);
      method m_axis_rx_tkeep  tkeep   clocked_by(user_clk_out)    reset_by(no_reset);
      method m_axis_rx_tuser  tuser   clocked_by(user_clk_out)    reset_by(no_reset);
      method m_axis_rx_tvalid tvalid   clocked_by(user_clk_out)    reset_by(no_reset);
      method                  tready(m_axis_rx_tready)    enable((*inhigh*)en08)   clocked_by(user_clk_out)    reset_by(no_reset);
   endinterface
   interface PciewrapRx     rx;
      method                  np_ok(rx_np_ok)    enable((*inhigh*)en09)   clocked_by(user_clk_out)    reset_by(no_reset);
      method                  np_req(rx_np_req)    enable((*inhigh*)en10)   clocked_by(user_clk_out)    reset_by(no_reset);
   endinterface

   method                    cfg_dsn(cfg_dsn)    enable((*inhigh*)en25)   clocked_by(user_clk_out);

   interface PciewrapCfg     cfg;
      method cfg_bus_number      bus_number   clocked_by(no_clock) reset_by(no_reset);
      method cfg_device_number   device_number   clocked_by(no_clock) reset_by(no_reset);
      method cfg_function_number function_number   clocked_by(no_clock) reset_by(no_reset);
      method cfg_lcommand        lcommand   clocked_by(user_clk_out) reset_by(no_reset);
      method                     interrupt(cfg_interrupt)    enable((*inhigh*)en32)   clocked_by(user_clk_out) reset_by(no_reset);

      method cfg_bridge_serr_en bridge_serr_en();
      method cfg_command command();
      method cfg_dcommand dcommand();
      method cfg_dcommand2 dcommand2();
      method cfg_lstatus lstatus();
      method cfg_pcie_link_state pcie_link_state();
      method pciecap_interrupt_msgnum(cfg_pciecap_interrupt_msgnum) enable((*inhigh*) EN_cfg_pciecap_interrupt_msgnum);
      method cfg_received_func_lvl_rst received_func_lvl_rst();
      method cfg_slot_control_electromech_il_ctl_pulse slot_control_electromech_il_ctl_pulse();
      method cfg_status status();
      method cfg_to_turnoff to_turnoff();
      method trn_pending(cfg_trn_pending) enable((*inhigh*) EN_cfg_trn_pending);
      method turnoff_ok(cfg_turnoff_ok) enable((*inhigh*) EN_cfg_turnoff_ok);
      method cfg_vc_tcvc_map vc_tcvc_map();
   endinterface

   output_clock pipe_txoutclk_out(pipe_txoutclk_out);

   schedule (user_lnk_up, user_app_rdy, fc_ph, fc_pd, fc_nph, fc_npd, fc_cplh, fc_cpld, fc_sel, s_axis_tx_tlast,
	     s_axis_tx_tdata, s_axis_tx_tkeep, s_axis_tx_tvalid, s_axis_tx_tready, s_axis_tx_tuser, tx_buf_av, tx_err_drop,
	     tx_cfg_req, tx_cfg_gnt, m_axis_rx_tlast, m_axis_rx_tdata, m_axis_rx_tkeep, m_axis_rx_tuser, m_axis_rx_tvalid,
	     m_axis_rx_tready, rx_np_ok, rx_np_req,
	     cfg_bus_number, cfg_device_number, cfg_function_number, cfg_lcommand,
cfg_command, cfg_dcommand, cfg_dcommand2, cfg_lstatus, cfg_pcie_link_state, cfg_received_func_lvl_rst, cfg_status, cfg_to_turnoff, cfg_vc_tcvc_map,
cfg_bridge_serr_en, cfg_slot_control_electromech_il_ctl_pulse,
cfg_pciecap_interrupt_msgnum, cfg_trn_pending, cfg_turnoff_ok,
cfg_interrupt, cfg_dsn,
	     pcie_txp, pcie_txn, pcie_rxp, pcie_rxn, pipe_mmcm_lock_in, pipe_pclk_sel_out
	     ) CF
            (user_lnk_up, user_app_rdy, fc_ph, fc_pd, fc_nph, fc_npd, fc_cplh, fc_cpld, fc_sel, s_axis_tx_tlast,
	     s_axis_tx_tdata, s_axis_tx_tkeep, s_axis_tx_tvalid, s_axis_tx_tready, s_axis_tx_tuser, tx_buf_av, tx_err_drop,
	     tx_cfg_req, tx_cfg_gnt, m_axis_rx_tlast, m_axis_rx_tdata, m_axis_rx_tkeep, m_axis_rx_tuser, m_axis_rx_tvalid,
	     m_axis_rx_tready, rx_np_ok, rx_np_req,
	     cfg_bus_number, cfg_device_number, cfg_function_number, cfg_lcommand,
cfg_command, cfg_dcommand, cfg_dcommand2, cfg_lstatus, cfg_pcie_link_state, cfg_received_func_lvl_rst, cfg_status, cfg_to_turnoff, cfg_vc_tcvc_map,
cfg_bridge_serr_en, cfg_slot_control_electromech_il_ctl_pulse,
cfg_pciecap_interrupt_msgnum, cfg_trn_pending, cfg_turnoff_ok,
cfg_interrupt, cfg_dsn,
	     pcie_txp, pcie_txn, pcie_rxp, pcie_rxn, pipe_mmcm_lock_in, pipe_pclk_sel_out
             );

endmodule: vMkXilinx7PCIExpress

////////////////////////////////////////////////////////////////////////////////
/// Interfaces
////////////////////////////////////////////////////////////////////////////////

interface PcieEndpointX7#(numeric type lanes);
   interface PciewrapPci_exp#(lanes)   pcie;
   interface PciewrapUser#(lanes)      user;
   interface PciewrapCfg#(lanes)       cfg;
   interface Server#(TLPData#(16), TLPData#(16)) tlp;
   interface Clock epClock125;
   interface Reset epReset125;
   interface Clock epClock250;
   interface Reset epReset250;
   interface Clock epPcieClock;
   interface Reset epPcieReset;
   interface Clock epPortalClock;
   interface Reset epPortalReset;
   interface Clock epDerivedClock;
   interface Reset epDerivedReset;
endinterface

typedef struct {
   Bit#(22)      user;
   Bit#(1)       last;
   Bit#(8)       keep;
   Bit#(64)      data;
} AxiRx deriving (Bits, Eq);

typedef struct {
   Bit#(1)       last;
   Bit#(8)       keep;
   Bit#(64)      data;
} AxiTx deriving (Bits, Eq);

`ifdef Artix7
typedef 4 PcieLanes;
`endif
`ifdef BOARD_zc706
typedef 4 PcieLanes;
`endif
`ifdef BOARD_vc707
typedef 8 PcieLanes;
`endif
`ifdef BOARD_kc705
typedef 8 PcieLanes;
`endif
`ifdef BOARD_kc160
typedef 8 PcieLanes;
`endif
`ifdef BOARD_nfsume
typedef 8 PcieLanes;
`endif

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

   PCIEParams params = defaultValue;

   ////////////////////////////////////////////////////////////////////////////////
   /// Design Elements
   ////////////////////////////////////////////////////////////////////////////////
   B2C1 b2c <- mkB2C1();
   ClockGenerator7AdvParams   clockParams = defaultValue;
   clockParams.bandwidth          = "OPTIMIZED";
   clockParams.compensation       = "INTERNAL";
   clockParams.clkfbout_mult_f    = 10.000;
   clockParams.clkfbout_phase     = 0.0;
   clockParams.clkin1_period      = 10.000;
   clockParams.clkout0_divide_f   = 8.000;
   clockParams.clkout0_duty_cycle = 0.5;
   clockParams.clkout0_phase      = 0.0000;
   clockParams.clkout1_divide     = 4;
   clockParams.clkout1_duty_cycle = 0.5;
   clockParams.clkout1_phase      = 0.0000;
   clockParams.clkout2_divide     = 4;
   clockParams.clkout2_duty_cycle = 0.5;
   clockParams.clkout2_phase      = 0.0000;
   clockParams.divclk_divide      = 1;
   clockParams.ref_jitter1        = 0.010;
   clockParams.clkin_buffer = False;
   XClockGenerator7   clockGen <- mkClockGenerator7Adv(clockParams, clocked_by b2c.c);
   C2B c2b_fb <- mkC2B(clockGen.clkfbout, clocked_by clockGen.clkfbout);
   rule txoutrule5;
      clockGen.clkfbin(c2b_fb.o());
   endrule

   Reset defaultReset <- exposeCurrentReset();
   Bufgctrl bbufc <- mkBufgctrl(clockGen.clkout0, defaultReset, clockGen.clkout1, defaultReset);
   Reset rsto <- mkAsyncReset(2, defaultReset, bbufc.o);
   Reg#(Bit#(1)) pclk_sel <- mkReg(0, clocked_by bbufc.o, reset_by rsto);
   Reg#(Bit#(PcieLanes)) pclk_sel_reg1 <- mkReg(0, clocked_by bbufc.o, reset_by rsto);
   Reg#(Bit#(PcieLanes)) pclk_sel_reg2 <- mkReg(0, clocked_by bbufc.o, reset_by rsto);

   rule bufcruleinit;
      bbufc.ce0(1);
      bbufc.ce1(1);
      bbufc.ignore0(0);
      bbufc.ignore1(0);
   endrule
   rule bufcrule;
      bbufc.s0(~pclk_sel);
      bbufc.s1(pclk_sel);
   endrule

   PCIE_X7#(PcieLanes) pcie_ep <- vMkXilinx7PCIExpress(params, clockGen.clkout0, clockGen.clkout2, bbufc.o);
   //new PcieWrap#(PcieLanes)  pciew <- mkPcieWrap();

   FIFOF#(AxiTx)             fAxiTx              <- mkBypassFIFOF(clocked_by pcie_ep.user.clk_out, reset_by noReset);
   FIFOF#(AxiRx)             fAxiRx              <- mkBypassFIFOF(clocked_by pcie_ep.user.clk_out, reset_by noReset);

   (* fire_when_enabled, no_implicit_conditions *)
   rule every1;
      pcie_ep.fc.sel(0 /*RECEIVE_BUFFER_AVAILABLE_SPACE*/);
      pcie_ep.cfg_dsn({ 32'h0000_0001, {{ 8'h1 } , 24'h000A35 }});
      pcie_ep.rx.np_ok(1);
      pcie_ep.rx.np_req(1);
      pcie_ep.tx.cfg_gnt(1);
      pcie_ep.s_axis_tx.tuser(4'b0);
      pcie_ep.m_axis_rx.tready(pack(fAxiRx.notFull));
   endrule
   rule every2;
      pcie_ep.pipe_mmcm_lock_in(pack(clockGen.locked));
   endrule
   rule every3;
      pclk_sel_reg1 <= pcie_ep.pipe_pclk_sel_out();
   endrule

   Clock txoutclk_buf <- mkClockBUFG(clocked_by pcie_ep.pipe_txoutclk_out);

   C2B c2b <- mkC2B(txoutclk_buf);
   rule txoutrule;
      b2c.inputclock(c2b.o());
   endrule

   rule update_psel;
       let ps = pclk_sel;
       pclk_sel_reg2 <= pclk_sel_reg1;
       if ((~pclk_sel_reg2) == 0)
           ps = 1;
       else if (pclk_sel_reg2 == 0)
           ps = 0;
       pclk_sel <= ps;
   endrule

   let txready = (pcie_ep.s_axis_tx.tready != 0 && fAxiTx.notEmpty);

   //(* fire_when_enabled, no_implicit_conditions *)
   rule drive_axi_tx if (txready);
      let info = fAxiTx.first; fAxiTx.deq;
      pcie_ep.s_axis_tx.tvalid(1);
      pcie_ep.s_axis_tx.tlast(info.last);
      pcie_ep.s_axis_tx.tdata(info.data);
      pcie_ep.s_axis_tx.tkeep(info.keep);
   endrule

   (* fire_when_enabled, no_implicit_conditions *)
   rule drive_axi_tx2 if (!txready);
      pcie_ep.s_axis_tx.tvalid(0);
      pcie_ep.s_axis_tx.tlast(0);
      pcie_ep.s_axis_tx.tdata(0);
      pcie_ep.s_axis_tx.tkeep(0);
   endrule

   (* fire_when_enabled *)
   rule sink_axi_rx if (pcie_ep.m_axis_rx.tvalid != 0);
      fAxiRx.enq(AxiRx {user: pcie_ep.m_axis_rx.tuser,
                        last: pcie_ep.m_axis_rx.tlast,
                        keep: pcie_ep.m_axis_rx.tkeep,
                        data: pcie_ep.m_axis_rx.tdata });
   endrule

   // The PCIe endpoint exports full (250MHz) and half-speed (125MHz) clocks
   Clock clock250 = pcie_ep.user.clk_out;
   Reset user_reset_n <- mkResetInverter(pcie_ep.user.reset_out, clocked_by clock250);
   Reset reset250 <- mkAsyncReset(4, user_reset_n, clock250);

   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 = 8.000; //  125MHz
   clkgenParams.clkout1_divide     = round(derivedClockPeriod);
   clkgenParams.clkout1_duty_cycle = 0.5;
   clkgenParams.clkout1_phase      = 0.0000;
   ClockGenerator7           clkgen <- mkClockGenerator7(clkgenParams, clocked_by clock250, reset_by user_reset_n);
   Clock clock125 = clkgen.clkout0; /* half speed user_clk */
   Reset reset125 <- mkAsyncReset(4, user_reset_n, clock125);
   Clock derivedClock = clkgen.clkout1;
   Reset derivedReset <- mkAsyncReset(4, user_reset_n, derivedClock);

   Server#(TLPData#(8), TLPData#(8)) tlp8 = (interface Server;
						interface Put request;
						   method Action put(TLPData#(8) data);
						      fAxiTx.enq(AxiTx {last: pack(data.eof),
									keep: dwordSwap64BE(data.be), data: dwordSwap64(data.data) });
						   endmethod
						endinterface
						interface Get response;
						   method ActionValue#(TLPData#(8)) get();
						      let info <- toGet(fAxiRx).get;
						      TLPData#(8) retval = defaultValue;
						      retval.sof  = (info.user[14] == 1);
						      retval.eof  = info.last != 0;
						      retval.hit  = info.user[8:2];
						      retval.be= dwordSwap64BE(info.keep);
						      retval.data = dwordSwap64(info.data);
						      return retval;
						   endmethod
						endinterface
					     endinterface);

`ifdef PCIE_250MHZ
   Clock portalClock = clock250;
   Reset portalReset = reset250;
`else
   Clock portalClock = clock125;
   Reset portalReset = reset125;
`endif
   // The PCIE endpoint is processing TLPData#(8)s at 250MHz.  The
   // AXI bridge is accepting TLPData#(16)s at 125 MHz. The
   // connection between the endpoint and the AXI contains GearBox
   // instances for the TLPData#(8)@250 <--> TLPData#(16)@125
   // conversion.
   PcieGearbox gb <- mkPcieGearbox(clock250, reset250, portalClock, portalReset);
   mkConnection(tlp8, gb.tlp, clocked_by portalClock, reset_by portalReset);

   interface tlp = gb.pci;
   interface pcie    = pcie_ep.pcie;
   interface PciewrapUser user = pcie_ep.user;
   interface PciewrapCfg cfg = pcie_ep.cfg;
   interface Clock epClock125 = clock125;
   interface Reset epReset125 = reset125;
   interface Clock epClock250 = clock250;
   interface Reset epReset250 = reset250;
   interface Clock epPcieClock = clock125;
   interface Reset epPcieReset = reset125;
   interface Clock epPortalClock = portalClock;
   interface Reset epPortalReset = portalReset;
   interface Clock epDerivedClock = derivedClock;
   interface Reset epDerivedReset = derivedReset;
endmodule: mkPcieEndpointX7

endpackage: PcieEndpointX7


cleanupdebug imageon Git: 7d8bf50ae47dd2fc8b1097524b7f2a80258f01c0

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

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

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

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

import Vector::*;
import Clocks :: *;
import XilinxCells::*;
import XbsvXilinxCells::*;

interface Iserdesbvi;
    method Action           align_start(Bit#(1) v);
    method Bit#(1)          align_busy();
    method Bit#(1)          aligned();
    method Bit#(3)          samplein();
    method Bit#(3)          iodelay_reset_inc_ce();
    method Bit#(1)          bitslip();
    method Action           autoalign(Bit#(1) v);
    method Action           training(Bit#(10) v);
    method Action           manual_tap(Bit#(10) v);
    method Action           delay_wren(Bit#(1) v);
    method Action           fifo_wren(Bit#(1) v);
    method Action           reset(Bit#(1) v);
    method Bit#(1)          fifo_wren_sync();
    method Action           dataout(Bit#(10) v);
    method Bit#(1)          itemreq();
    method Bit#(1)          ctrl_bitslip();
    method Bit#(1)          ctrl_fifo_reset();
    method Bit#(3)          ctrl_reset_inc_ce();
    method Action           dackint(Bit#(1) v);
endinterface: Iserdesbvi

import "BVI" iserdes_datadeser =
module mkIserdesbvi#(Clock clkdiv)(Iserdesbvi);
    input_clock clkdiv (CLKDIV) = clkdiv;
    default_clock clock(CLOCK);
    method                  align_start(ALIGN_START) enable((*inhigh*) en1) clocked_by (clock);
    method ALIGN_BUSY       align_busy() clocked_by (clock);
    method ALIGNED          aligned() clocked_by (clock);
    method ISERDES_BITSLIP  bitslip() clocked_by (clkdiv);
    method SAMPLEIN samplein() clocked_by (clock);
    method IODELAY_RESET_INC_CE iodelay_reset_inc_ce() clocked_by (clkdiv);
    method                  autoalign(AUTOALIGN) enable((*inhigh*) en7) clocked_by (clock);
    method                  training(TRAINING) enable((*inhigh*) en8) clocked_by (clock);
    method                  manual_tap(MANUAL_TAP) enable((*inhigh*) en9) clocked_by (clock);
    method                  fifo_wren(FIFO_WREN) enable((*inhigh*) en10) clocked_by (clkdiv);
    method FIFO_WREN_SYNC   fifo_wren_sync() clocked_by (clock);
    method                  delay_wren(DELAY_WREN) enable((*inhigh*) en11) clocked_by (clkdiv);
    method                  reset(RESET) enable((*inhigh*) en17) clocked_by (clkdiv);
    method                  dataout(ISERDES_DATA) enable((*inhigh*) en18) clocked_by(clkdiv);
    method ITEMREQ_o        itemreq() clocked_by(clkdiv);
    method CTRL_BITSLIP_o   ctrl_bitslip() clocked_by(clkdiv);
    method CTRL_FIFO_RESET_o   ctrl_fifo_reset() clocked_by(clkdiv);
    method CTRL_RESET_INC_CE_o ctrl_reset_inc_ce() clocked_by(clkdiv);
    method                  dackint(DACKINT) enable((*inhigh*) en19) clocked_by(clkdiv);
    schedule (dackint, ctrl_reset_inc_ce, itemreq, ctrl_bitslip, ctrl_fifo_reset, fifo_wren, reset, delay_wren, dataout, iodelay_reset_inc_ce, bitslip, align_busy, aligned, samplein, fifo_wren_sync, align_start, autoalign, training, manual_tap, bitslip)
         CF (dackint, ctrl_reset_inc_ce, itemreq, ctrl_bitslip, ctrl_fifo_reset, fifo_wren, reset, delay_wren, dataout, iodelay_reset_inc_ce, bitslip, align_busy, aligned, samplein, fifo_wren_sync, align_start, autoalign, training, manual_tap, bitslip);
endmodule: mkIserdesbvi

interface IserdesDatadeser;
    method Action           ibufdso(Bit#(1) v);
    method Bit#(1)          align_busy();
    method Bit#(1)          aligned();
    method Bit#(1)          sampleinfirstbit();
    method Bit#(1)          sampleinlastbit();
    method Bit#(1)          sampleinotherbit();
    method Action           delay_wren(Bit#(1) v);
    method Action           fifo_wren(Bit#(1) v);
    method Action           reset(Bit#(1) v);
    method Bit#(1)          empty();
    method Bit#(10)         dataout();
endinterface: IserdesDatadeser

interface FIFO18;
   method Action            di(Bit#(16) v);
   method Action            rden(Bit#(1) v);
   method Action            wren(Bit#(1) v);
   method Action            reset(Bit#(1) v);
   method Bit#(16)          dataout();
   method Bit#(1)           empty();
endinterface: FIFO18

import "BVI" FIFO18 =
module mkFIFO18#(Clock clkdiv)(FIFO18);
    parameter ALMOST_FULL_OFFSET = 'h80;
    parameter ALMOST_EMPTY_OFFSET = 'h80;
    parameter DATA_WIDTH = 18;
    parameter DO_REG = 1;
    parameter EN_SYN = 0;
    parameter FIRST_WORD_FALL_THROUGH = 0;
    parameter SIM_MODE = "SAFE";

    default_clock clock(RDCLK);
    input_clock clkdiv (WRCLK) = clkdiv;
    no_reset;
    port DIP = 0;

    method          reset(RST) enable((*inhigh*) en9) clocked_by (clkdiv);
    method          di(DI) enable((*inhigh*) en0) clocked_by (clkdiv);
    method          rden(RDEN) enable((*inhigh*) en2) clocked_by (clock);
    method          wren(WREN) enable((*inhigh*) en3) clocked_by (clock);
    method DO       dataout() clocked_by(clock);
    method EMPTY    empty() clocked_by(clock);
    schedule (reset, di, rden, wren, dataout, empty) CF (reset, di, rden, wren, dataout, empty);
endmodule: mkFIFO18

typedef enum { DIdle, DValid, DLow} DState deriving (Bits,Eq);

module mkIserdesDatadeser#(Clock serdes_clock, Reset serdes_reset, Clock serdest, Bit#(1) align_start,
    Bit#(1) autoalign, Bit#(10) training, Bit#(10) manual_tap, Bit#(1) rden)(IserdesDatadeser);

    Clock defaultClock <- exposeCurrentClock();
    Reset defaultReset <- exposeCurrentReset();
    Iserdesbvi serbvi <- mkIserdesbvi(serdes_clock);
    FIFO18 dfifo <- mkFIFO18(serdes_clock);
    IdelayE2 delaye2 <- mkIDELAYE2(IDELAYE2_Config {
        cinvctrl_sel: "FALSE", delay_src: "IDATAIN",
        high_performance_mode: "TRUE",
        idelay_type: "VARIABLE", idelay_value: 0,
        pipe_sel: "FALSE", refclk_frequency: 200, signal_pattern: "DATA"},
        defaultClock, clocked_by serdes_clock);
    ClockDividerIfc serdest_inverted <- mkClockInverter(clocked_by serdest);
    IserdesE2 master_data <- mkISERDESE2( ISERDESE2_Config{
        data_rate: "DDR", data_width: 10,
        dyn_clk_inv_en: "FALSE", dyn_clkdiv_inv_en: "FALSE",
        interface_type: "NETWORKING", num_ce: 2, ofb_used: "FALSE",
        init_q1: 0, init_q2: 0, init_q3: 0, init_q4: 0,
        srval_q1: 0, srval_q2: 0, srval_q3: 0, srval_q4: 0,
        serdes_mode: "MASTER", iobdelay: "IFD"},
        serdest, serdest_inverted.slowClock, clocked_by serdes_clock);
    IserdesE2 slave_data <- mkISERDESE2( ISERDESE2_Config{
        data_rate: "DDR", data_width: 10,
        dyn_clk_inv_en: "FALSE", dyn_clkdiv_inv_en: "FALSE",
        interface_type: "NETWORKING", num_ce: 2, ofb_used: "FALSE",
        init_q1: 0, init_q2: 0, init_q3: 0, init_q4: 0,
        srval_q1: 0, srval_q2: 0, srval_q3: 0, srval_q4: 0,
        serdes_mode: "SLAVE", iobdelay: "NONE"},
        serdest, serdest_inverted.slowClock, clocked_by serdes_clock);
    Wire#(Bit#(1)) bvi_delay_wren_wire <- mkDWire(0, clocked_by serdes_clock, reset_by serdes_reset);
    Wire#(Bit#(1)) bvi_reset_reg <- mkDWire(0, clocked_by serdes_clock, reset_by serdes_reset);
    Wire#(Bit#(1)) bvi_fifo_wren_wire <- mkDWire(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(3)) dcounter <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(10)) iserdes_data <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(DState)  dstate <- mkReg(DIdle, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) dreqpipe0 <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) dreqpipe1 <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) fifo_reset <- mkReg(1, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) dfifo_reset_r <- mkReg(1, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) dfifo_wren_r <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) fifo_wren_sync <- mkSyncReg(0, serdes_clock, serdes_reset, defaultClock);
    Reg#(Bit#(1)) sync_bitslip <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(3)) sync_reset_inc_ce <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Wire#(Bit#(1)) fifo_wren_sync_wire <- mkDWire(0);
//, clocked_by serdes_clock, reset_by serdes_reset);
    //outputs
    Reg#(Bit#(1)) dackint <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    ReadOnly#(Bit#(3)) samplein_null <- mkNullCrossingWire(serdes_clock, serbvi.samplein());

    //Reg#(Bit#(1)) iserdes_bitslip <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    //Reg#(Bit#(3)) iodelay_reset_inc_ce <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Wire#(Bit#(1)) iserdes_bitslip <- mkDWire(0, clocked_by serdes_clock, reset_by serdes_reset);
    Wire#(Bit#(3)) iodelay_reset_inc_ce <- mkDWire(0, clocked_by serdes_clock, reset_by serdes_reset);

    rule wren_rule;
        //fifo_wren_sync_wire <= fifo_wren_sync;
        fifo_wren_sync_wire <= serbvi.fifo_wren_sync();
    endrule
    rule clkdiv_rule if (bvi_reset_reg != 0);
        let ds = dstate;
        let dc = dcounter;
        let da = dackint;
        let sric = sync_reset_inc_ce;
        let sbs = 0;
        let fwsync = 0;

        dc = dc - 1;
        dreqpipe0 <= serbvi.itemreq();
        dreqpipe1 <= dreqpipe0;
        dfifo_reset_r <= serbvi.ctrl_fifo_reset();
        fifo_reset <= dfifo_reset_r;
        dfifo_wren_r <= bvi_fifo_wren_wire;
        if (bvi_delay_wren_wire == 1 && samplein_null[2] == 1)
            fwsync = dfifo_wren_r;
        else
            fwsync = bvi_fifo_wren_wire;
        sric[0] = 0;
        sric[1] = 0;
        //iodelay_reset_inc_ce <= sync_reset_inc_ce;
        //iserdes_bitslip <= sync_bitslip;
        iodelay_reset_inc_ce <= serbvi.iodelay_reset_inc_ce();
        iserdes_bitslip <= serbvi.bitslip();
        if (dstate == DIdle && dreqpipe1 == 1)
            begin
            sric = serbvi.ctrl_reset_inc_ce();
            sbs = serbvi.ctrl_bitslip();
            dc = 3'b011;
            ds = DValid;
            end
        if (dstate == DValid && dcounter[2] == 1)
            begin
            da = 1;
            ds = DLow;
            end
        if (dstate == DLow && dreqpipe1 == 0)
            begin
            da = 0;
            ds = DIdle;
            end
        dstate <= ds;
        dcounter <= dc;
        dackint <= da;
        sync_reset_inc_ce <= sric;
        sync_bitslip <= sbs;
        fifo_wren_sync <= fwsync;
        serbvi.dackint(dackint);
    endrule

    rule setrule;
        dfifo.reset(iodelay_reset_inc_ce[2]);
        delaye2.reset(iodelay_reset_inc_ce[2]);
        delaye2.cinvctrl(0);
        delaye2.cntvaluein(0);
        delaye2.ld(0);
        delaye2.ldpipeen(0);
        delaye2.datain(0);
        delaye2.inc(iodelay_reset_inc_ce[1] == 1);
        delaye2.ce(iodelay_reset_inc_ce[0]);
    endrule

    rule serdesdata_rule;
        let dout = 10'b0;
        master_data.d(0);
        master_data.bitslip(iserdes_bitslip);
        master_data.ce1(1);
        master_data.ce2(1);
        master_data.ddly(delaye2.dataout());
        master_data.ofb(0);
        master_data.dynclkdivsel(0);
        master_data.dynclksel(0);
        master_data.shiftin1(0);
        master_data.shiftin2(0);
        master_data.oclk(0);
        master_data.oclkb(0);
        master_data.reset(iodelay_reset_inc_ce[2]);
        slave_data.d(0);
        slave_data.bitslip(iserdes_bitslip);
        slave_data.ce1(1);
        slave_data.ce2(1);
        slave_data.ddly(0);
        slave_data.ofb(0);
        slave_data.dynclkdivsel(0);
        slave_data.dynclksel(0);
        slave_data.shiftin1(master_data.shiftout1());
        slave_data.shiftin2(master_data.shiftout2());
        dout = {slave_data.q4(), slave_data.q3(), master_data.q8(),
           master_data.q7(), master_data.q6(), master_data.q5(),
           master_data.q4(), master_data.q3(), master_data.q2(), master_data.q1()};
        slave_data.oclk(0);
        slave_data.oclkb(0);
        slave_data.reset(iodelay_reset_inc_ce[2]);
        iserdes_data <= dout;
        serbvi.dataout(dout);
        dfifo.di({6'b0,dout});
    endrule
    //rule bozodata_rule;
        //serbvi.dataout(iserdes_data);
    //endrule

    rule wren_dfifo_rule;
        dfifo.wren(fifo_wren_sync_wire);
    endrule

    rule serdesrule;
        serbvi.align_start(align_start);
        serbvi.autoalign(autoalign);
        serbvi.training(training);
        serbvi.manual_tap(manual_tap);
        dfifo.rden(rden);
    endrule

    method Action ibufdso(Bit#(1) v);
        delaye2.idatain(v);
    endmethod
    method Bit#(1)                align_busy();
        return serbvi.align_busy();
    endmethod
    method Bit#(1)                aligned();
        return serbvi.aligned();
    endmethod
    method Bit#(1)                sampleinfirstbit();
        return serbvi.samplein()[2];
    endmethod
    method Bit#(1)                sampleinlastbit();
        return serbvi.samplein()[1];
    endmethod
    method Bit#(1)                sampleinotherbit();
        return serbvi.samplein()[0];
    endmethod
    method Action                 delay_wren(Bit#(1) v);
        bvi_delay_wren_wire <= v;
        serbvi.delay_wren(v);
    endmethod
    method Action                 fifo_wren(Bit#(1) v);
        bvi_fifo_wren_wire <= v;
        serbvi.fifo_wren(v);
    endmethod
    method Action                 reset(Bit#(1) v);
        bvi_reset_reg <= v;
        serbvi.reset(v);
    endmethod
    method Bit#(1)                empty();
        return dfifo.empty();
    endmethod
    method Bit#(10)               dataout();
        return dfifo.dataout()[9:0];
    endmethod
endmodule: mkIserdesDatadeser

(* always_enabled *)
interface ImageonSerdesPins;
    method Action io_vita_sync_p(Bit#(1) v);
    method Action io_vita_sync_n(Bit#(1) v);
    method Action io_vita_data_p(Bit#(4) v);
    method Action io_vita_data_n(Bit#(4) v);
    method Action io_vita_clk_p(Bit#(1) v);
    method Action io_vita_clk_n(Bit#(1) v);
endinterface

interface ImageonSerdesControl;
    method Action set_decoder_control(Bit#(32) v);
    method Action set_iserdes_control(Bit#(32) v);
    method Action set_serdes_manual_tap(Bit#(10) v);
    method Action set_serdes_training(Bit#(10) v);
    method Bit#(32) get_iserdes_control();
endinterface

interface SerdesData;
    method Wire#(Bit#(1)) reset();
    method Bit#(1) raw_empty();
    method Bit#(50) raw_data();
endinterface

interface ISerdes;
    interface ImageonSerdesControl control;
    interface ImageonSerdesPins pins;
    interface SerdesData data;
endinterface

module mkISerdes#(Clock axi_clock, Reset axi_reset)(ISerdes);
    Clock defaultClock <- exposeCurrentClock();
    Reset defaultReset <- exposeCurrentReset();

    Wire#(Bit#(1)) vita_clk_p <- mkDWire(0);
    Wire#(Bit#(1)) vita_clk_n <- mkDWire(0);
    Clock ibufds_clk <- mkClockIBUFDS(vita_clk_p, vita_clk_n);
    ClockGenIfc serdes_clk <- mkBUFR5(ibufds_clk);
    Clock serdes_clock = serdes_clk.gen_clk;
    Reset serdes_reset <- mkAsyncReset(2, defaultReset, serdes_clock);

    Vector#(5, Wire#(Bit#(1))) vita_data_p <- replicateM(mkDWire(0));
    Vector#(5, Wire#(Bit#(1))) vita_data_n <- replicateM(mkDWire(0));
    Reg#(Bit#(1)) decoder_enable_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(1)) serdes_auto_align_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(1)) serdes_align_start_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(1)) serdes_fifo_enable_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    ReadOnly#(Bit#(1)) serdes_fifo_enable_null <- mkNullCrossingWire(serdes_clock, serdes_fifo_enable_reg);
    Reg#(Bit#(10)) serdes_manual_tap_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(10)) serdes_training_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(1)) serdes_reset_reg <- mkSyncReg(1, axi_clock, axi_reset, defaultClock);
    ReadOnly#(Bit#(1)) serdes_reset_null <- mkNullCrossingWire(serdes_clock, serdes_reset_reg);

    Wire#(Bit#(50)) raw_data_wire <- mkDWire(0);

    Wire#(Bit#(1)) empty_wire <- mkDWire(0);
    Wire#(Bit#(1)) bittest_wire <- mkDWire(0);
    Reg#(Bit#(1)) delay_wren_r_reg <-mkReg(0);
    Reg#(Bit#(1)) delay_wren_r2_reg <- mkSyncReg(0, defaultClock, defaultReset, serdes_clock);
    Reg#(Bit#(1)) delay_wren_c_reg <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) fifo_wren_r2_reg <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) fifo_wren_c_reg <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);

    ClockGenIfc serdest_clk <- mkBUFIO(ibufds_clk);
    Vector#(5, ReadOnly#(Bit#(1))) ibufds_v;
    for (Integer i = 0; i < 5; i = i + 1)
        ibufds_v[i] <- mkIBUFDS(vita_data_p[i], vita_data_n[i]);
    Reg#(Bit#(1)) serdes_align_busy_temp <- mkReg(0);
    Reg#(Bit#(1)) serdes_align_busy_reg <- mkSyncReg(0, defaultClock, defaultReset, axi_clock);
    Reg#(Bit#(1)) serdes_aligned_temp <- mkReg(0);
    Reg#(Bit#(1)) serdes_aligned_reg <- mkSyncReg(0, defaultClock, defaultReset, axi_clock);
    Wire#(Bit#(1)) new_raw_empty_wire <- mkDWire(0);
    Vector#(5, IserdesDatadeser) serdes_v <- replicateM(mkIserdesDatadeser(serdes_clock, serdes_reset, serdest_clk.gen_clk,
	  serdes_align_start_reg, serdes_auto_align_reg, serdes_training_reg,
	  serdes_manual_tap_reg, decoder_enable_reg));

    rule serdes_copybits;
        serdes_aligned_reg <= serdes_aligned_temp;
        serdes_align_busy_reg <= serdes_align_busy_temp;
    endrule

    rule sendup_imageon_clock;
       Bit#(5) alignbusyw = 0;
       Bit#(5) alignedw = 0;
       Bit#(5) firstw = 0;
       Bit#(5) lastw = 0;
       Bit#(5) otherw = 0;
       Bit#(5) emptyw = 0;
       Bit#(50) rawdataw = 0;
       for (Bit#(8) i = 0; i < 5; i = i+1) begin
	  serdes_v[i].ibufdso(ibufds_v[i]);
	  alignbusyw[i] = serdes_v[i].align_busy();
	  alignedw[i] = serdes_v[i].aligned();
	  firstw[i] = serdes_v[i].sampleinfirstbit();
	  lastw[i] = serdes_v[i].sampleinlastbit();
	  otherw[i] = serdes_v[i].sampleinotherbit();
	  emptyw[i] = serdes_v[i].empty();
	  rawdataw[(i+1)*10-1: i*10] = serdes_v[i].dataout();
       end
       serdes_align_busy_temp <= pack(alignbusyw != 0);
       serdes_aligned_temp <= pack(alignedw == 5'b11111);
       bittest_wire <= pack(otherw == 0 && firstw != 0 && lastw != 0);
       empty_wire <= pack(emptyw != 0);
       raw_data_wire <= rawdataw;
    endrule

    rule sendup_sdes_clock;
    for (Bit#(8) i = 0; i < 5; i = i+1) begin
       serdes_v[i].reset(serdes_reset_null);
       serdes_v[i].delay_wren(delay_wren_c_reg);
       serdes_v[i].fifo_wren(serdes_fifo_enable_null);
    end
    endrule

    rule serdes_reset_rule if (serdes_reset_reg == 0);
        new_raw_empty_wire <= 0;
        delay_wren_r_reg <= 0;
        delay_wren_r2_reg <= 0;
    endrule

    rule serdes_resetc_rule if (serdes_reset_null == 0);
        delay_wren_c_reg <= 0;
        fifo_wren_r2_reg <= 0;
        fifo_wren_c_reg <= 0;
    endrule

    rule serdes_calc2 if (serdes_reset_reg == 1);
        new_raw_empty_wire <= empty_wire;
        delay_wren_r_reg <= bittest_wire;
        delay_wren_r2_reg <= delay_wren_r_reg;
    endrule

    rule serdes_calc2c if (serdes_reset_null == 1);
        delay_wren_c_reg <= delay_wren_r2_reg;
        fifo_wren_r2_reg <= serdes_fifo_enable_null;
        fifo_wren_c_reg <= fifo_wren_r2_reg;
    endrule

    interface ImageonSerdesControl control;
	method Action set_serdes_manual_tap(Bit#(10) v);
	    serdes_manual_tap_reg <= v;
	endmethod
	method Action set_serdes_training(Bit#(10) v);
	    serdes_training_reg <= v;
	endmethod
	method Action set_iserdes_control(Bit#(32) v);
	    serdes_reset_reg <= ~v[0];
	    serdes_auto_align_reg <= v[1];
	    serdes_align_start_reg <= v[2];
	    serdes_fifo_enable_reg <= v[3];
	endmethod
	method Bit#(32) get_iserdes_control();
	    let v = 0;
	    v[8] = 1;
	    v[9] = serdes_align_busy_reg;
	    v[10] = serdes_aligned_reg;
	    return v;
	endmethod
	method Action set_decoder_control(Bit#(32) v);
	    decoder_enable_reg <= v[1];
	endmethod
    endinterface

    interface ImageonSerdesPins pins;
        method Action io_vita_sync_p(Bit#(1) v);
            vita_data_p[0] <= v;
        endmethod
        method Action io_vita_sync_n(Bit#(1) v);
            vita_data_n[0] <= v;
        endmethod
        method Action io_vita_data_p(Bit#(4) v);
            for (Integer i = 0; i < 4; i = i + 1)
                vita_data_p[i+1] <= v[i];
        endmethod
        method Action io_vita_data_n(Bit#(4) v);
            for (Integer i = 0; i < 4; i = i + 1)
                vita_data_n[i+1] <= v[i];
        endmethod
        method Action io_vita_clk_p(Bit#(1) v);
            vita_clk_p <= v;
        endmethod
        method Action io_vita_clk_n(Bit#(1) v);
            vita_clk_n <= v;
        endmethod
    endinterface
    interface SerdesData data;
        method Wire#(Bit#(1)) reset();
            return serdes_reset_reg;
        endmethod
        method Bit#(1) raw_empty();
            return new_raw_empty_wire;
        endmethod
        method Bit#(50) raw_data();
            return raw_data_wire;
	endmethod
    endinterface
endmodule

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

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

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

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

import Vector::*;
import Clocks :: *;
import XilinxCells::*;
import XbsvXilinxCells::*;

interface Iserdesbvi;
    method Action           align_start(Bit#(1) v);
    method Bit#(1)          align_busy();
    method Bit#(1)          aligned();
    method Bit#(3)          samplein();
    method Bit#(3)          iodelay_reset_inc_ce();
    method Bit#(1)          bitslip();
    method Action           autoalign(Bit#(1) v);
    method Action           training(Bit#(10) v);
    method Action           manual_tap(Bit#(10) v);
    method Action           delay_wren(Bit#(1) v);
    method Action           fifo_wren(Bit#(1) v);
    method Action           reset(Bit#(1) v);
    method Bit#(1)          fifo_wren_sync();
    method Action           dataout(Bit#(10) v);
    method Bit#(1)          itemreq();
    method Bit#(1)          ctrl_bitslip();
    method Bit#(1)          ctrl_fifo_reset();
    method Bit#(3)          ctrl_reset_inc_ce();
    method Action           dackint(Bit#(1) v);
endinterface: Iserdesbvi

import "BVI" iserdes_datadeser =
module mkIserdesbvi#(Clock clkdiv)(Iserdesbvi);
    input_clock clkdiv (CLKDIV) = clkdiv;
    default_clock clock(CLOCK);
    method                  align_start(ALIGN_START) enable((*inhigh*) en1) clocked_by (clock);
    method ALIGN_BUSY       align_busy() clocked_by (clock);
    method ALIGNED          aligned() clocked_by (clock);
    method ISERDES_BITSLIP  bitslip() clocked_by (clkdiv);
    method SAMPLEIN samplein() clocked_by (clock);
    method IODELAY_RESET_INC_CE iodelay_reset_inc_ce() clocked_by (clkdiv);
    method                  autoalign(AUTOALIGN) enable((*inhigh*) en7) clocked_by (clock);
    method                  training(TRAINING) enable((*inhigh*) en8) clocked_by (clock);
    method                  manual_tap(MANUAL_TAP) enable((*inhigh*) en9) clocked_by (clock);
    method                  fifo_wren(FIFO_WREN) enable((*inhigh*) en10) clocked_by (clkdiv);
    method FIFO_WREN_SYNC   fifo_wren_sync() clocked_by (clock);
    method                  delay_wren(DELAY_WREN) enable((*inhigh*) en11) clocked_by (clkdiv);
    method                  reset(RESET) enable((*inhigh*) en17) clocked_by (clkdiv);
    method                  dataout(ISERDES_DATA) enable((*inhigh*) en18) clocked_by(clkdiv);
    method ITEMREQ_o        itemreq() clocked_by(clkdiv);
    method CTRL_BITSLIP_o   ctrl_bitslip() clocked_by(clkdiv);
    method CTRL_FIFO_RESET_o   ctrl_fifo_reset() clocked_by(clkdiv);
    method CTRL_RESET_INC_CE_o ctrl_reset_inc_ce() clocked_by(clkdiv);
    method                  dackint(DACKINT) enable((*inhigh*) en19) clocked_by(clkdiv);
    schedule (dackint, ctrl_reset_inc_ce, itemreq, ctrl_bitslip, ctrl_fifo_reset, fifo_wren, reset, delay_wren, dataout, iodelay_reset_inc_ce, bitslip, align_busy, aligned, samplein, fifo_wren_sync, align_start, autoalign, training, manual_tap, bitslip)
         CF (dackint, ctrl_reset_inc_ce, itemreq, ctrl_bitslip, ctrl_fifo_reset, fifo_wren, reset, delay_wren, dataout, iodelay_reset_inc_ce, bitslip, align_busy, aligned, samplein, fifo_wren_sync, align_start, autoalign, training, manual_tap, bitslip);
endmodule: mkIserdesbvi

interface IserdesDatadeser;
    method Action           ibufdso(Bit#(1) v);
    method Bit#(1)          align_busy();
    method Bit#(1)          aligned();
    method Bit#(1)          sampleinfirstbit();
    method Bit#(1)          sampleinlastbit();
    method Bit#(1)          sampleinotherbit();
    method Action           delay_wren(Bit#(1) v);
    method Action           fifo_wren(Bit#(1) v);
    method Action           reset(Bit#(1) v);
    method Bit#(1)          empty();
    method Bit#(10)         dataout();
endinterface: IserdesDatadeser

interface FIFO18;
   method Action            di(Bit#(16) v);
   method Action            rden(Bit#(1) v);
   method Action            wren(Bit#(1) v);
   method Action            reset(Bit#(1) v);
   method Bit#(16)          dataout();
   method Bit#(1)           empty();
endinterface: FIFO18

import "BVI" FIFO18 =
module mkFIFO18#(Clock clkdiv)(FIFO18);
    parameter ALMOST_FULL_OFFSET = 'h80;
    parameter ALMOST_EMPTY_OFFSET = 'h80;
    parameter DATA_WIDTH = 18;
    parameter DO_REG = 1;
    parameter EN_SYN = 0;
    parameter FIRST_WORD_FALL_THROUGH = 0;
    parameter SIM_MODE = "SAFE";

    default_clock clock(RDCLK);
    input_clock clkdiv (WRCLK) = clkdiv;
    no_reset;
    port DIP = 0;

    method          reset(RST) enable((*inhigh*) en9) clocked_by (clkdiv);
    method          di(DI) enable((*inhigh*) en0) clocked_by (clkdiv);
    method          rden(RDEN) enable((*inhigh*) en2) clocked_by (clock);
    method          wren(WREN) enable((*inhigh*) en3) clocked_by (clock);
    method DO       dataout() clocked_by(clock);
    method EMPTY    empty() clocked_by(clock);
    schedule (reset, di, rden, wren, dataout, empty) CF (reset, di, rden, wren, dataout, empty);
endmodule: mkFIFO18

typedef enum { DIdle, DValid, DLow} DState deriving (Bits,Eq);

module mkIserdesDatadeser#(Clock serdes_clock, Reset serdes_reset, Clock serdest, Bit#(1) align_start,
    Bit#(1) autoalign, Bit#(10) training, Bit#(10) manual_tap, Bit#(1) rden)(IserdesDatadeser);

    Clock defaultClock <- exposeCurrentClock();
    Reset defaultReset <- exposeCurrentReset();
    Iserdesbvi serbvi <- mkIserdesbvi(serdes_clock);
    FIFO18 dfifo <- mkFIFO18(serdes_clock);
    IdelayE2 delaye2 <- mkIDELAYE2(IDELAYE2_Config {
        cinvctrl_sel: "FALSE", delay_src: "IDATAIN",
        high_performance_mode: "TRUE",
        idelay_type: "VARIABLE", idelay_value: 0,
        pipe_sel: "FALSE", refclk_frequency: 200, signal_pattern: "DATA"},
        defaultClock, clocked_by serdes_clock);
    ClockDividerIfc serdest_inverted <- mkClockInverter(clocked_by serdest);
    IserdesE2 master_data <- mkISERDESE2( ISERDESE2_Config{
        data_rate: "DDR", data_width: 10,
        dyn_clk_inv_en: "FALSE", dyn_clkdiv_inv_en: "FALSE",
        interface_type: "NETWORKING", num_ce: 2, ofb_used: "FALSE",
        init_q1: 0, init_q2: 0, init_q3: 0, init_q4: 0,
        srval_q1: 0, srval_q2: 0, srval_q3: 0, srval_q4: 0,
        serdes_mode: "MASTER", iobdelay: "IFD"},
        serdest, serdest_inverted.slowClock, clocked_by serdes_clock);
    IserdesE2 slave_data <- mkISERDESE2( ISERDESE2_Config{
        data_rate: "DDR", data_width: 10,
        dyn_clk_inv_en: "FALSE", dyn_clkdiv_inv_en: "FALSE",
        interface_type: "NETWORKING", num_ce: 2, ofb_used: "FALSE",
        init_q1: 0, init_q2: 0, init_q3: 0, init_q4: 0,
        srval_q1: 0, srval_q2: 0, srval_q3: 0, srval_q4: 0,
        serdes_mode: "SLAVE", iobdelay: "NONE"},
        serdest, serdest_inverted.slowClock, clocked_by serdes_clock);
    Wire#(Bit#(1)) bvi_delay_wren_wire <- mkDWire(0, clocked_by serdes_clock, reset_by serdes_reset);
    Wire#(Bit#(1)) bvi_reset_reg <- mkDWire(0, clocked_by serdes_clock, reset_by serdes_reset);
    Wire#(Bit#(1)) bvi_fifo_wren_wire <- mkDWire(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(3)) dcounter <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(10)) iserdes_data <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(DState)  dstate <- mkReg(DIdle, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) dreqpipe0 <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) dreqpipe1 <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) fifo_reset <- mkReg(1, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) dfifo_reset_r <- mkReg(1, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) dfifo_wren_r <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) fifo_wren_sync <- mkSyncReg(0, serdes_clock, serdes_reset, defaultClock);
    Reg#(Bit#(1)) sync_bitslip <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(3)) sync_reset_inc_ce <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    //outputs
    Reg#(Bit#(1)) iserdes_bitslip <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) dackint <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(3)) iodelay_reset_inc_ce <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    ReadOnly#(Bit#(3)) samplein_null <- mkNullCrossingWire(serdes_clock, serbvi.samplein());

    rule clkdiv_rule if (bvi_reset_reg != 0);
        let ds = dstate;
        let dc = dcounter;
        let da = dackint;
        let sric = sync_reset_inc_ce;
        let sbs = 0;
        let fwsync = 0;

        dc = dc - 1;
        dreqpipe0 <= serbvi.itemreq();
        dreqpipe1 <= dreqpipe0;
        dfifo_reset_r <= serbvi.ctrl_fifo_reset();
        fifo_reset <= dfifo_reset_r;
        dfifo_wren_r <= bvi_fifo_wren_wire;
        if (bvi_delay_wren_wire == 1 && samplein_null[2] == 1)
            fwsync = dfifo_wren_r;
        else
            fwsync = bvi_fifo_wren_wire;
        sric[1] = 0;
        sric[2] = 0;
        iodelay_reset_inc_ce <= sync_reset_inc_ce;
        iserdes_bitslip <= sync_bitslip;
        if (dstate == DIdle && dreqpipe1 == 1)
            begin
            sric = serbvi.ctrl_reset_inc_ce();
            sbs = serbvi.ctrl_bitslip();
            dc = 3'b011;
            ds = DValid;
            end
        if (dstate == DValid && dcounter[2] == 1)
            begin
            da = 1;
            ds = DLow;
            end
        if (dstate == DLow && dreqpipe1 == 0)
            begin
            da = 0;
            ds = DIdle;
            end
        dstate <= ds;
        dcounter <= dc;
        dackint <= da;
        sync_reset_inc_ce <= sric;
        sync_bitslip <= sbs;
        fifo_wren_sync <= fwsync;
        serbvi.dackint(dackint);
    endrule

    rule setrule;
        dfifo.reset(serbvi.iodelay_reset_inc_ce()[2]);
        delaye2.reset(serbvi.iodelay_reset_inc_ce()[2]);
        //dfifo.reset(iodelay_reset_inc_ce[2]);
        //delaye2.reset(iodelay_reset_inc_ce[2]);
        delaye2.cinvctrl(0);
        delaye2.cntvaluein(0);
        delaye2.ld(0);
        delaye2.ldpipeen(0);
        delaye2.datain(0);
        delaye2.inc(serbvi.iodelay_reset_inc_ce()[1] == 1);
        delaye2.ce(serbvi.iodelay_reset_inc_ce()[0]);
        //delaye2.inc(iodelay_reset_inc_ce[1] == 1);
        //delaye2.ce(iodelay_reset_inc_ce[0]);
    endrule

    rule serdesdata_rule;
        let dout = 10'b0;
        master_data.d(0);
        master_data.bitslip(serbvi.bitslip());
        //master_data.bitslip(iserdes_bitslip);
        master_data.ce1(1);
        master_data.ce2(1);
        master_data.ddly(delaye2.dataout());
        master_data.ofb(0);
        master_data.dynclkdivsel(0);
        master_data.dynclksel(0);
        master_data.shiftin1(0);
        master_data.shiftin2(0);
        master_data.oclk(0);
        master_data.oclkb(0);
        master_data.reset(serbvi.iodelay_reset_inc_ce()[2]);
        //master_data.reset(iodelay_reset_inc_ce[2]);
        slave_data.d(0);
        slave_data.bitslip(serbvi.bitslip());
        //slave_data.bitslip(iserdes_bitslip);
        slave_data.ce1(1);
        slave_data.ce2(1);
        slave_data.ddly(0);
        slave_data.ofb(0);
        slave_data.dynclkdivsel(0);
        slave_data.dynclksel(0);
        slave_data.shiftin1(master_data.shiftout1());
        slave_data.shiftin2(master_data.shiftout2());
        dout = {slave_data.q4(), slave_data.q3(), master_data.q8(),
           master_data.q7(), master_data.q6(), master_data.q5(),
           master_data.q4(), master_data.q3(), master_data.q2(), master_data.q1()};
        slave_data.oclk(0);
        slave_data.oclkb(0);
        slave_data.reset(serbvi.iodelay_reset_inc_ce()[2]);
        //slave_data.reset(iodelay_reset_inc_ce[2]);
        iserdes_data <= dout;
        serbvi.dataout(dout);
        dfifo.di({6'b0,dout});
    endrule
    //rule bozodata_rule;
        //serbvi.dataout(iserdes_data);
    //endrule

    rule wren_dfifo_rule;
        dfifo.wren(serbvi.fifo_wren_sync());
        //dfifo.wren(fifo_wren_sync);
    endrule

    rule serdesrule;
        serbvi.align_start(align_start);
        serbvi.autoalign(autoalign);
        serbvi.training(training);
        serbvi.manual_tap(manual_tap);
        dfifo.rden(rden);
    endrule

    method Action ibufdso(Bit#(1) v);
        delaye2.idatain(v);
    endmethod
    method Bit#(1)                align_busy();
        return serbvi.align_busy();
    endmethod
    method Bit#(1)                aligned();
        return serbvi.aligned();
    endmethod
    method Bit#(1)                sampleinfirstbit();
        return serbvi.samplein()[2];
    endmethod
    method Bit#(1)                sampleinlastbit();
        return serbvi.samplein()[1];
    endmethod
    method Bit#(1)                sampleinotherbit();
        return serbvi.samplein()[0];
    endmethod
    method Action                 delay_wren(Bit#(1) v);
        bvi_delay_wren_wire <= v;
        serbvi.delay_wren(v);
    endmethod
    method Action                 fifo_wren(Bit#(1) v);
        bvi_fifo_wren_wire <= v;
        serbvi.fifo_wren(v);
    endmethod
    method Action                 reset(Bit#(1) v);
        bvi_reset_reg <= v;
        serbvi.reset(v);
    endmethod
    method Bit#(1)                empty();
        return dfifo.empty();
    endmethod
    method Bit#(10)               dataout();
        return dfifo.dataout()[9:0];
    endmethod
endmodule: mkIserdesDatadeser

(* always_enabled *)
interface ImageonSerdesPins;
    method Action io_vita_sync_p(Bit#(1) v);
    method Action io_vita_sync_n(Bit#(1) v);
    method Action io_vita_data_p(Bit#(4) v);
    method Action io_vita_data_n(Bit#(4) v);
    method Action io_vita_clk_p(Bit#(1) v);
    method Action io_vita_clk_n(Bit#(1) v);
endinterface

interface ImageonSerdesControl;
    method Action set_decoder_control(Bit#(32) v);
    method Action set_iserdes_control(Bit#(32) v);
    method Action set_serdes_manual_tap(Bit#(10) v);
    method Action set_serdes_training(Bit#(10) v);
    method Bit#(32) get_iserdes_control();
endinterface

interface SerdesData;
    method Wire#(Bit#(1)) reset();
    method Bit#(1) raw_empty();
    method Bit#(50) raw_data();
endinterface

interface ISerdes;
    interface ImageonSerdesControl control;
    interface ImageonSerdesPins pins;
    interface SerdesData data;
endinterface

module mkISerdes#(Clock axi_clock, Reset axi_reset)(ISerdes);
    Clock defaultClock <- exposeCurrentClock();
    Reset defaultReset <- exposeCurrentReset();

    Wire#(Bit#(1)) vita_clk_p <- mkDWire(0);
    Wire#(Bit#(1)) vita_clk_n <- mkDWire(0);
    Clock ibufds_clk <- mkClockIBUFDS(vita_clk_p, vita_clk_n);
    ClockGenIfc serdes_clk <- mkBUFR5(ibufds_clk);
    Clock serdes_clock = serdes_clk.gen_clk;
    Reset serdes_reset <- mkAsyncReset(2, defaultReset, serdes_clock);

    Vector#(5, Wire#(Bit#(1))) vita_data_p <- replicateM(mkDWire(0));
    Vector#(5, Wire#(Bit#(1))) vita_data_n <- replicateM(mkDWire(0));
    Reg#(Bit#(1)) decoder_enable_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(1)) serdes_auto_align_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(1)) serdes_align_start_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(1)) serdes_fifo_enable_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    ReadOnly#(Bit#(1)) serdes_fifo_enable_null <- mkNullCrossingWire(serdes_clock, serdes_fifo_enable_reg);
    Reg#(Bit#(10)) serdes_manual_tap_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(10)) serdes_training_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(1)) serdes_reset_reg <- mkSyncReg(1, axi_clock, axi_reset, defaultClock);
    ReadOnly#(Bit#(1)) serdes_reset_null <- mkNullCrossingWire(serdes_clock, serdes_reset_reg);

    Wire#(Bit#(50)) raw_data_wire <- mkDWire(0);

    Wire#(Bit#(1)) empty_wire <- mkDWire(0);
    Wire#(Bit#(1)) bittest_wire <- mkDWire(0);
    Reg#(Bit#(1)) delay_wren_r_reg <-mkReg(0);
    Reg#(Bit#(1)) delay_wren_r2_reg <- mkSyncReg(0, defaultClock, defaultReset, serdes_clock);
    Reg#(Bit#(1)) delay_wren_c_reg <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) fifo_wren_r2_reg <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) fifo_wren_c_reg <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);

    ClockGenIfc serdest_clk <- mkBUFIO(ibufds_clk);
    Vector#(5, ReadOnly#(Bit#(1))) ibufds_v;
    for (Integer i = 0; i < 5; i = i + 1)
        ibufds_v[i] <- mkIBUFDS(vita_data_p[i], vita_data_n[i]);
    Reg#(Bit#(1)) serdes_align_busy_temp <- mkReg(0);
    Reg#(Bit#(1)) serdes_align_busy_reg <- mkSyncReg(0, defaultClock, defaultReset, axi_clock);
    Reg#(Bit#(1)) serdes_aligned_temp <- mkReg(0);
    Reg#(Bit#(1)) serdes_aligned_reg <- mkSyncReg(0, defaultClock, defaultReset, axi_clock);
    Wire#(Bit#(1)) new_raw_empty_wire <- mkDWire(0);
    Vector#(5, IserdesDatadeser) serdes_v <- replicateM(mkIserdesDatadeser(serdes_clock, serdes_reset, serdest_clk.gen_clk,
	  serdes_align_start_reg, serdes_auto_align_reg, serdes_training_reg,
	  serdes_manual_tap_reg, decoder_enable_reg));

    rule serdes_copybits;
        serdes_aligned_reg <= serdes_aligned_temp;
        serdes_align_busy_reg <= serdes_align_busy_temp;
    endrule

    rule sendup_imageon_clock;
       Bit#(5) alignbusyw = 0;
       Bit#(5) alignedw = 0;
       Bit#(5) firstw = 0;
       Bit#(5) lastw = 0;
       Bit#(5) otherw = 0;
       Bit#(5) emptyw = 0;
       Bit#(50) rawdataw = 0;
       for (Bit#(8) i = 0; i < 5; i = i+1) begin
	  serdes_v[i].ibufdso(ibufds_v[i]);
	  alignbusyw[i] = serdes_v[i].align_busy();
	  alignedw[i] = serdes_v[i].aligned();
	  firstw[i] = serdes_v[i].sampleinfirstbit();
	  lastw[i] = serdes_v[i].sampleinlastbit();
	  otherw[i] = serdes_v[i].sampleinotherbit();
	  emptyw[i] = serdes_v[i].empty();
	  rawdataw[(i+1)*10-1: i*10] = serdes_v[i].dataout();
       end
       serdes_align_busy_temp <= pack(alignbusyw != 0);
       serdes_aligned_temp <= pack(alignedw == 5'b11111);
       bittest_wire <= pack(otherw == 0 && firstw != 0 && lastw != 0);
       empty_wire <= pack(emptyw != 0);
       raw_data_wire <= rawdataw;
    endrule

    rule sendup_sdes_clock;
    for (Bit#(8) i = 0; i < 5; i = i+1) begin
       serdes_v[i].reset(serdes_reset_null);
       serdes_v[i].delay_wren(delay_wren_c_reg);
       serdes_v[i].fifo_wren(serdes_fifo_enable_null);
    end
    endrule

    rule serdes_reset_rule if (serdes_reset_reg == 0);
        new_raw_empty_wire <= 0;
        delay_wren_r_reg <= 0;
        delay_wren_r2_reg <= 0;
    endrule

    rule serdes_resetc_rule if (serdes_reset_null == 0);
        delay_wren_c_reg <= 0;
        fifo_wren_r2_reg <= 0;
        fifo_wren_c_reg <= 0;
    endrule

    rule serdes_calc2 if (serdes_reset_reg == 1);
        new_raw_empty_wire <= empty_wire;
        delay_wren_r_reg <= bittest_wire;
        delay_wren_r2_reg <= delay_wren_r_reg;
    endrule

    rule serdes_calc2c if (serdes_reset_null == 1);
        delay_wren_c_reg <= delay_wren_r2_reg;
        fifo_wren_r2_reg <= serdes_fifo_enable_null;
        fifo_wren_c_reg <= fifo_wren_r2_reg;
    endrule

    interface ImageonSerdesControl control;
	method Action set_serdes_manual_tap(Bit#(10) v);
	    serdes_manual_tap_reg <= v;
	endmethod
	method Action set_serdes_training(Bit#(10) v);
	    serdes_training_reg <= v;
	endmethod
	method Action set_iserdes_control(Bit#(32) v);
	    serdes_reset_reg <= ~v[0];
	    serdes_auto_align_reg <= v[1];
	    serdes_align_start_reg <= v[2];
	    serdes_fifo_enable_reg <= v[3];
	endmethod
	method Bit#(32) get_iserdes_control();
	    let v = 0;
	    v[8] = 1;
	    v[9] = serdes_align_busy_reg;
	    v[10] = serdes_aligned_reg;
	    return v;
	endmethod
	method Action set_decoder_control(Bit#(32) v);
	    decoder_enable_reg <= v[1];
	endmethod
    endinterface

    interface ImageonSerdesPins pins;
        method Action io_vita_sync_p(Bit#(1) v);
            vita_data_p[0] <= v;
        endmethod
        method Action io_vita_sync_n(Bit#(1) v);
            vita_data_n[0] <= v;
        endmethod
        method Action io_vita_data_p(Bit#(4) v);
            for (Integer i = 0; i < 4; i = i + 1)
                vita_data_p[i+1] <= v[i];
        endmethod
        method Action io_vita_data_n(Bit#(4) v);
            for (Integer i = 0; i < 4; i = i + 1)
                vita_data_n[i+1] <= v[i];
        endmethod
        method Action io_vita_clk_p(Bit#(1) v);
            vita_clk_p <= v;
        endmethod
        method Action io_vita_clk_n(Bit#(1) v);
            vita_clk_n <= v;
        endmethod
    endinterface
    interface SerdesData data;
        method Wire#(Bit#(1)) reset();
            return serdes_reset_reg;
        endmethod
        method Bit#(1) raw_empty();
            return new_raw_empty_wire;
        endmethod
        method Bit#(50) raw_data();
            return raw_data_wire;
	endmethod
    endinterface
endmodule