/******************************************************************************
* Copyright                                                                   *
* Scintillating Fibre Beam Profile Monitor Software by Michal Dziewiecki,     *
* Blake Leverington and Liqing Qin is licensed under CC BY 4.0                *
* https://creativecommons.org/licenses/by/4.0/                                *
* funded by the Deutsche Forschungsgemeinschaft                               *
* (DFG, German Research Foundation) Projektnummer 419255448                   *
* Project Leader: B.Leverington                                               *
*******************************************************************************
* Create Date - 2019                                                          *
* Author: M.Dziewiecki                                                        *
* Module - m10_rgmii.v                                                        *
* Edited by L.Qin on Oct 15. 2024 for reconstruction                          *
******************************************************************************/

module  m10_rgmii (
        //Clock and Reset
        input  wire        clk_50_max10,
        input  wire        fpga_resetn,
		  

        //LED PB DIPSW
        output wire [4:0]  user_led,
        input  wire [3:0]  user_pb,
        input  wire [4:0]  user_dipsw,

        //Dual Ethernet
        output wire        enet_mdc,
        inout  wire        enet_mdio,	
        output wire        enet_resetn,	
        input  wire        enet_rx_clk,
        input  wire        enet_tx_clk,
        output wire        enet_gtx_clk,
        input  wire [3:0]  enet_rx_d,
        output wire [3:0]  enet_tx_d,
        output wire        enet_tx_en,
        input  wire        enet_rx_dv,
        input  wire        enet_led_link100,
 
		  input  wire        ddr3_ram_pll_ref_clk_clk,                    //                ddr3_ram_pll_ref_clk.clk
	
        output wire [13:0] mem_a,
        output wire [2:0]  mem_ba,
        inout  wire [0:0]  mem_ck,
        inout  wire [0:0]  mem_ck_n,
        output wire [0:0]  mem_cke,
        output wire [0:0]  mem_cs_n,
        output wire [0:0]  mem_dm,
        output wire [0:0]  mem_ras_n,
        output wire [0:0]  mem_cas_n,
        output wire [0:0]  mem_we_n,
        output wire        mem_reset_n,
        inout  wire [7:0]  mem_dq,
        inout  wire [0:0]  mem_dqs,
        inout  wire [0:0]  mem_dqs_n,
        output wire [0:0]  mem_odt,

        //QSPI
        output          qspi_clk,
        inout  [3:0]    qspi_io,
        output          qspi_csn,
			
		//Sensors
		output wire [1:0] sensor_reset,
		output wire [1:0] sensor_clk,
		input  wire [4:0] sensor_trig,
		output wire [1:0] adc_cnv,
		output wire [1:0] adc_sck,
		input  wire [4:0] adc_sdo,
		output wire	  sensor_gainp,
		output wire	  sensor_gainn,
		
		//Synchro
		input  wire [3:0] link_rx,
		output wire [3:0] link_tx,
		output wire [3:0] link_dir,
			
			  
		  //PMOD
		input wire  [7:0] pmoda,	//used for 8-fold SMA input;)
		output wire [7:0] pmodb,
			  
	  //USB UART
	  output wire		  debug_txd,
	  input wire		  debug_rxd		  
		  
        );

//*********************************** Signals *************************************
	
//Heart-beat counter
reg   [25:0]  heart_beat_cnt;

//DDR3 interface assignments
wire          local_init_done;
wire          local_cal_success;
wire          local_cal_fail;

//Ethernet interface assignments
wire          phy_resetn;
wire          system_resetn;

wire          mdio_oen_from_the_tse_mac;
wire          mdio_out_from_the_tse_mac;
wire          eth_mode_from_the_tse_mac;
wire          ena_10_from_the_tse_mac;
wire          enet_tx_125;
wire          enet_tx_25;
wire          enet_tx_2p5;
wire          locked_from_the_enet_pll;
wire          tx_clk_to_the_tse_mac;
wire          tx_clk_to_the_tse_mac_g;

wire          enet_tx_125_shift;
wire          enet_tx_25_shift;
wire          enet_tx_2p5_shift;
wire          enet_tx_250_shift; // signaltap sample clock
wire          locked_from_the_shift_pll;
wire          tx_clk_to_the_tse_mac_shift;
wire          tx_clk_to_the_tse_mac_shift_g;

//User interface ;)
wire [8:0]	user_input;
wire [7:0]	int_output;

//Sensor interface
wire        int_sensor_in_trg;                               
wire        int_sensor_out_adc_clk;
wire        int_sensor_out_adc_cnv;
wire [4:0]  int_sensor_in_adc_data;
wire        int_sensor_out_sensor_rst;
wire        int_sensor_out_sensor_clk;
wire        int_sensor_out_sensor_gain;
wire [7:0]  int_sensor_status;


//Trigger stuff
wire	    int_frame_timer;
reg	    sym_frame_timer;

//*********************************** Sensor connections *************************************

assign sensor_reset[0] 	= int_sensor_out_sensor_rst;
assign sensor_reset[1] 	= int_sensor_out_sensor_rst;
assign sensor_clk[0]	= ~int_sensor_out_sensor_clk;
assign sensor_clk[1]	= ~int_sensor_out_sensor_clk;
assign sensor_gainp	= int_sensor_out_sensor_gain;
assign sensor_gainn	= ~int_sensor_out_sensor_gain;
assign adc_cnv[0]	= int_sensor_out_adc_cnv;
assign adc_cnv[1]	= int_sensor_out_adc_cnv;
assign adc_sck[0]	= ~int_sensor_out_adc_clk;
assign adc_sck[1]	= ~int_sensor_out_adc_clk;
assign int_sensor_in_adc_data = adc_sdo;	//all of them are not-inverted :)


//*********************************** Frame trigger & synchro routing (master/slave) *************************************

//Synchro pulse is LINK3 (inverted)
//Global counter transmission is LINK2 (inverted)

wire trig_mode;
assign trig_mode = int_output[7];
wire int_synchro_rx;
wire int_synchro_tx;
wire int_trig_debouncer_in;
wire int_ser_debouncer_in;

	//Pulse flip-flop
always @(posedge int_frame_timer or negedge fpga_resetn)
begin
	if (!fpga_resetn)
		sym_frame_timer <= 0; 
	else if (trig_mode == 0)
		sym_frame_timer <= 0;
	else
		sym_frame_timer <= ~sym_frame_timer;
end
	//Trigger Assignments
assign link_dir[3]		= trig_mode;		//set link direction according to M/S setting (LED PIO 7)
assign link_tx[3]		= ~sym_frame_timer;	//connect internal frame trigger to TX
assign int_trig_debouncer_in 	= trig_mode ? sym_frame_timer : link_rx[3];	//connect either internal or external frame trigger

	//Debouncer for trigger signals - limit trigger bandwidth to 2.5 MHz
debouncer #(
	.LENGTH	(10)
) trig_debouncer (
	.rst	(!system_resetn),
	.clk	(clk_50_max10),
	.in	(int_trig_debouncer_in),
	.out	(int_sensor_in_trg)
);

	//Serial assignments
assign link_dir[2]		= trig_mode;
assign int_ser_debouncer_in   	= trig_mode ? int_synchro_tx : link_rx[2];
assign link_tx[2] 		= ~int_synchro_tx;

	//Debouncer for serial RX - limit bandwidth to 2.5 MHz
debouncer #(
	.LENGTH	(10)
) ser_debouncer (
	.rst	(!system_resetn),
	.clk	(clk_50_max10),
	.in	(int_ser_debouncer_in),
	.out	(int_synchro_rx)
);
	
	
//*********************************** Various logic *************************************

assign system_resetn = fpga_resetn & local_init_done;

	//PMOD debug lines
assign pmodb[0] 	= int_trig_debouncer_in;
assign pmodb[1] 	= int_sensor_in_trg;
assign pmodb[7:2] 	= int_sensor_status[5:0];

	//Buttons/switches
assign user_input[3:0] = user_pb[3:0];
assign user_input[8:4] = user_dipsw[4:0];

//LED forwarding
assign user_led[3:0] = ~int_output[3:0];
	//disable user_led[4] blink with int_output[5]; force user_led[4] with int_output[4]
assign user_led[4] = ~int_output[4] & (heart_beat_cnt[25] | int_output[5]);	
	//int_output[6] is used for PHY hard reset
	//int_output[7] is used for master/slave frame trigger routing

	
//Heart beat by 50MHz clock
always @(posedge clk_50_max10 or negedge fpga_resetn)
  if (!fpga_resetn)
      heart_beat_cnt <= 26'h0; //0x3FFFFFF
  else
      heart_beat_cnt <= heart_beat_cnt + 1'b1;


		
//*********************************** Ethernet *************************************	
	
	//PHY power-on reset control
parameter MSB = 20; // PHY interface: need minimum 10ms delay for POR
reg [MSB:0] epcount;

always @(posedge clk_50_max10 or negedge fpga_resetn)
  if (!fpga_resetn)
      epcount <= MSB + 1'b0;
  else if (epcount[MSB] == 1'b0)
      epcount <= epcount + 1;
  else
      epcount <= epcount;

assign phy_resetn    = user_pb[0] & !(int_output[6] & epcount[MSB]) & !epcount[MSB-1];		//PHY hard reset by counter, user button or software
assign enet_resetn   = phy_resetn;

//MDIO output control
assign enet_mdio = ( !mdio_oen_from_the_tse_mac ) ? ( mdio_out_from_the_tse_mac ) : ( 1'bz );

assign enet_tx_2p5_shift = !enet_tx_2p5;

//RGMII clock solution
assign tx_clk_to_the_tse_mac = ( eth_mode_from_the_tse_mac ) ? ( enet_tx_125 ) :  // GbE Mode = 125MHz clock
                               ( ena_10_from_the_tse_mac ) ? ( enet_tx_2p5 ) :    // 10Mb Mode = 2.5MHz clock
                               ( enet_tx_25 );                                    // 100Mb Mode = 25MHz clock

assign tx_clk_to_the_tse_mac_shift = ( eth_mode_from_the_tse_mac ) ? ( enet_tx_125_shift ) :  // GbE Mode = 125MHz clock
                                     ( ena_10_from_the_tse_mac ) ? ( enet_tx_2p5_shift ) :    // 10Mb Mode = 2.5MHz clock
                                     ( enet_tx_25_shift);                                     // 100Mb Mode = 25MHz clock

clkctrl             clkctrl_inst0 (
                    .inclk        (tx_clk_to_the_tse_mac  ),
                    .outclk       (tx_clk_to_the_tse_mac_g)
                    );

clkctrl             clkctrl_inst1 (
                    .inclk        (tx_clk_to_the_tse_mac_shift  ),
                    .outclk       (tx_clk_to_the_tse_mac_shift_g)
                    );

enet_gtx_clk_ddio   enet_gtx_clk_ddio_inst (
                    .outclock              (tx_clk_to_the_tse_mac_shift_g), // tx_clk_to_the_tse_mac_g ),
                    .din                   (2'b10                        ),
                    .pad_out               (enet_gtx_clk                 ),
                    .aclr                  (!phy_resetn                  )
                    );

		    
//*********************************** Main QSYS *************************************
		    
q_sys               q_sys_inst (
                    .sys_clk_clk                                                   (clk_50_max10              ), //                             sys_clk.clk
                    .reset_reset_n                                                 (system_resetn             ), //                               reset.reset_n
                    .mem_resetn_in_reset_reset_n                                   (fpga_resetn               ), //                 mem_resetn_in_reset.reset_n
                    .altpll_shift_c0_clk                                           (enet_tx_250_shift         ), //                     altpll_shift_c0.clk
                    .altpll_shift_locked_conduit_export                            (locked_from_the_shift_pll ), //         altpll_shift_locked_conduit.export
                    .clock_bridge_0_in_clk_clk                                     (enet_tx_25                ), //               clock_bridge_0_in_clk.clk
                    .enet_pll_c0_clk                                               (enet_tx_125               ), //                         enet_pll_c0.clk
                    .enet_pll_c1_clk                                               (enet_tx_25                ), //                         enet_pll_c1.clk
                    .enet_pll_c2_clk                                               (enet_tx_2p5               ), //                         enet_pll_c2.clk
                    .enet_pll_c3_clk                                               (enet_tx_125_shift         ), //                         enet_pll_c3.clk
                    .enet_pll_c4_clk                                               (enet_tx_25_shift          ), //                         enet_pll_c4.clk
                    .enet_pll_locked_conduit_export                                (locked_from_the_enet_pll  ), //             enet_pll_locked_conduit.export
                    .eth_tse_mac_mdio_connection_mdc                               (enet_mdc                  ), //         eth_tse_mac_mdio_connection.mdc
                    .eth_tse_mac_mdio_connection_mdio_in                           (enet_mdio                 ), //                                    .mdio_in
                    .eth_tse_mac_mdio_connection_mdio_out                          (mdio_out_from_the_tse_mac ), //                                    .mdio_out
                    .eth_tse_mac_mdio_connection_mdio_oen                          (mdio_oen_from_the_tse_mac ), //                                    .mdio_oen
                    .eth_tse_mac_rgmii_connection_rgmii_in                         (enet_rx_d                 ), //        eth_tse_mac_rgmii_connection.rgmii_in
                    .eth_tse_mac_rgmii_connection_rgmii_out                        (enet_tx_d                 ), //                                    .rgmii_out
                    .eth_tse_mac_rgmii_connection_rx_control                       (enet_rx_dv                ), //                                    .rx_control
                    .eth_tse_mac_rgmii_connection_tx_control                       (enet_tx_en                ), //                                    .tx_control
                    .eth_tse_mac_status_connection_set_10                          (                          ), //       eth_tse_mac_status_connection.set_10
                    .eth_tse_mac_status_connection_set_1000                        (                          ), //                                    .set_1000
                    .eth_tse_mac_status_connection_eth_mode                        (eth_mode_from_the_tse_mac ), //                                    .eth_mode
                    .eth_tse_mac_status_connection_ena_10                          (ena_10_from_the_tse_mac   ), //                                    .ena_10
                    .eth_tse_pcs_mac_rx_clock_connection_clk                       (enet_rx_clk               ), // eth_tse_pcs_mac_rx_clock_connection.clk
                    .eth_tse_pcs_mac_tx_clock_connection_clk                       (tx_clk_to_the_tse_mac_g   ), // eth_tse_pcs_mac_tx_clock_connection.clk
                    .ext_flash_flash_dataout_conduit_dataout                       (qspi_io                   ), //             ext_flash_flash_dataout.conduit_dataout
                    .ext_flash_flash_dclk_out_conduit_dclk_out                     (qspi_clk                  ), //            ext_flash_flash_dclk_out.conduit_dclk_out
                    .ext_flash_flash_ncs_conduit_ncs                               (qspi_csn                  ), //                 ext_flash_flash_ncs.conduit_ncs
						  .ddr3_ram_pll_ref_clk_clk												  (ddr3_ram_pll_ref_clk_clk ),
                    .memory_mem_a                                                  (mem_a                     ), //                              memory.mem_a
                    .memory_mem_ba                                                 (mem_ba                    ), //                                    .mem_ba
                    .memory_mem_ck                                                 (mem_ck                    ), //                                    .mem_ck
                    .memory_mem_ck_n                                               (mem_ck_n                  ), //                                    .mem_ck_n
                    .memory_mem_cke                                                (mem_cke                   ), //                                    .mem_cke
                    .memory_mem_cs_n                                               (mem_cs_n                  ), //                                    .mem_cs_n
                    .memory_mem_dm                                                 (mem_dm                    ), //                                    .mem_dm
                    .memory_mem_ras_n                                              (mem_ras_n                 ), //                                    .mem_ras_n
                    .memory_mem_cas_n                                              (mem_cas_n                 ), //                                    .mem_cas_n
                    .memory_mem_we_n                                               (mem_we_n                  ), //                                    .mem_we_n
                    .memory_mem_reset_n                                            (mem_reset_n               ), //                                    .mem_reset_n
                    .memory_mem_dq                                                 (mem_dq                    ), //                                    .mem_dq
                    .memory_mem_dqs                                                (mem_dqs                   ), //                                    .mem_dqs
                    .memory_mem_dqs_n                                              (mem_dqs_n                 ), //                                    .mem_dqs_n
                    .memory_mem_odt                                                (mem_odt                   ), //                                    .mem_odt
                    .led_pio_external_connection_export                            (int_output[7:0]              ), //         led_pio_external_connection.export
                    .mem_if_ddr3_emif_0_status_local_init_done                     (local_init_done           ), //           mem_if_ddr3_emif_0_status.local_init_done
                    .mem_if_ddr3_emif_0_status_local_cal_success                   (local_cal_success         ), //                                    .local_cal_success
                    .mem_if_ddr3_emif_0_status_local_cal_fail                      (local_cal_fail            ), //                                    .local_cal_fail
                    .button_pio_external_connection_export			   (user_input	  	      ), //
		    .debug_uart_external_connection_rxd         		   (debug_rxd		      ), //      
		    .debug_uart_external_connection_txd         		   (debug_txd		      ), //
		    .sensor_in_trg 						   (int_sensor_in_trg	      ),                               
		    .sensor_out_adc_clk 					   (int_sensor_out_adc_clk    ),
		    .sensor_out_adc_cnv 					   (int_sensor_out_adc_cnv    ),
		    .sensor_in_adc_data 					   (int_sensor_in_adc_data    ),
		    .sensor_out_sensor_rst 					   (int_sensor_out_sensor_rst ),
		    .sensor_out_sensor_clk  					   (int_sensor_out_sensor_clk ),
		    .sensor_out_sensor_gain 					   (int_sensor_out_sensor_gain),
		    .frame_timer_export						   (int_frame_timer),
		    .sensor_synchro_serial_rx                    		   (int_synchro_rx),//                      sensor_synchro.serial_rx
		    .sensor_synchro_serial_tx                    		   (int_synchro_tx),//                                    .serial_tx
		    .sensor_synchro_ext_input				           (pmoda),
		    .sensor_status_status_out					   (int_sensor_status)
			);
						  
endmodule						  
