// ============================================================================
// Copyright (c) 2024 by Terasic Technologies Inc.
// ============================================================================
//
// Permission:
//
//   Terasic grants permission to use and modify this code for use
//   in synthesis for all Terasic Development Boards and Altera Development
//   Kits made by Terasic.  Other use of this code, including the selling
//   ,duplication, or modification of any portion is strictly prohibited.
//
// Disclaimer:
//
//   This VHDL/Verilog or C/C++ source code is intended as a design reference
//   which illustrates how these types of functions can be implemented.
//   It is the user's responsibility to verify their design for
//   consistency and functionality through the use of formal
//   verification methods.  Terasic provides no warranty regarding the use
//   or functionality of this code.
//
// ============================================================================
//
//  Terasic Technologies Inc
//  No.80, Fenggong Rd., Hukou Township, Hsinchu County 303035. Taiwan
//
//
//                     web: http://www.terasic.com/
//                     email: support@terasic.com
//
// ============================================================================
//Date:  Wed Apr  3 10:19:18 2024
// ============================================================================

`define ENABLE_DDR4A
//`define ENABLE_DDR4B
//`define ENABLE_QSFP
//`define ENABLE_FMCP
`define ENABLE_HPS
//`define ENABLE_HDMI
//`define ENABLE_PCIE
//`define ENABLE_ENET
//`define ENABLE_CAM1
//`define ENABLE_CAM2

module golden_top(

      ///////// CLOCK /////////
      input              CLK_100_B2B_p,
      input              CLK_50_B5A,
      input              CLK_50_B6A,
      input              CLK_50_B6C,

      ///////// Buttons /////////
      input              CPU_RESET_n,
      input    [ 3: 0]   BUTTON, //BUTTON is Low-Active

      ///////// Swtiches /////////
      input    [ 3: 0]   SW,

      ///////// LED /////////
      output   [ 3: 0]   LED, //LED is Low-Active

`ifdef ENABLE_DDR4A
      ///////// DDR4A /////////
      input              DDR4A_REFCLK_p,
      output   [16: 0]   DDR4A_A,
      output   [ 1: 0]   DDR4A_BA,
      output   [ 0: 0]   DDR4A_BG,
      output             DDR4A_CK,
      output             DDR4A_CK_n,
      output             DDR4A_CKE,
      inout    [ 3: 0]   DDR4A_DQS,
      inout    [ 3: 0]   DDR4A_DQS_n,
      inout    [31: 0]   DDR4A_DQ,
      inout    [ 3: 0]   DDR4A_DBI_n,
      output             DDR4A_CS_n,
      output             DDR4A_RESET_n,
      output             DDR4A_ODT,
      output             DDR4A_PAR,
      input              DDR4A_ALERT_n,
      output             DDR4A_ACT_n,
      input              DDR4A_RZQ,
`endif /*ENABLE_DDR4A*/

`ifdef ENABLE_DDR4B
      ///////// DDR4B /////////
      input              DDR4B_REFCLK_p,
      output   [16: 0]   DDR4B_A,
      output   [ 1: 0]   DDR4B_BA,
      output   [ 0: 0]   DDR4B_BG,
      output             DDR4B_CK,
      output             DDR4B_CK_n,
      output             DDR4B_CKE,
      inout    [ 3: 0]   DDR4B_DQS,
      inout    [ 3: 0]   DDR4B_DQS_n,
      inout    [31: 0]   DDR4B_DQ,
      inout    [ 3: 0]   DDR4B_DBI_n,
      output             DDR4B_CS_n,
      output             DDR4B_RESET_n,
      output             DDR4B_ODT,
      output             DDR4B_PAR,
      input              DDR4B_ALERT_n,
      output             DDR4B_ACT_n,
      input              DDR4B_RZQ,
`endif /*ENABLE_DDR4B*/

`ifdef ENABLE_HDMI
      ///////// HDMI /////////
      inout              HDMI_LRCLK,
      inout              HDMI_MCLK,
      inout              HDMI_SCLK,
      output             HDMI_TX_CLK,
      output             HDMI_TX_HS,
      output             HDMI_TX_VS,
      output   [23: 0]   HDMI_TX_D,
      output             HDMI_TX_DE,
      inout              HDMI_I2C_SCL,
      inout              HDMI_I2C_SDA,
      input              HDMI_TX_INT,
      inout              HDMI_I2S,
`endif /*ENABLE_HDMI*/

`ifdef ENABLE_ENET
      ///////// ENET /////////
      output             ENET_88E2110_TX_p,
      output             ENET_88E2110_TX_n,
      input              ENET_88E2110_RX_p,
      input              ENET_88E2110_RX_n,
      input              ENET_88E2110_REFCLK_125M_p,
      input              ENET_88E2110_INT_n,
      output             ENET_88E2110_MDC,
      inout              ENET_88E2110_MDIO,
      output             ENET_88E2110_RESET_n,
`endif /*ENABLE_ENET*/

      ///////// SI5340B /////////
      inout              SI5340B_I2C_SCL,
      inout              SI5340B_I2C_SDA,
      output             SI5340B_OE_n,
      output             SI5340B_RST_n,

      ///////// SI5391B /////////
      inout              SI5391B_I2C_SCL,
      inout              SI5391B_I2C_SDA,
      output             SI5391B_OE_n,
      output             SI5391B_RST_n,

      ///////// GPIO /////////
      inout    [35: 0]   GPIO,

      ///////// TMD /////////
      inout    [ 7: 0]   TMD_D,

`ifdef ENABLE_FMCP
      ///////// FMCP /////////
      inout              FMCP_CLK2_BIDIR_p,
      inout              FMCP_CLK2_BIDIR_n,
      inout              FMCP_CLK3_BIDIR_p,
      inout              FMCP_CLK3_BIDIR_n,
      output   [11: 0]   FMCP_DP_C2M_p,
      output   [11: 0]   FMCP_DP_C2M_n,
      input    [11: 0]   FMCP_DP_M2C_p,
      input    [11: 0]   FMCP_DP_M2C_n,
      inout    [23: 0]   FMCP_HA_p,
      inout    [23: 0]   FMCP_HA_n,
      inout    [21: 0]   FMCP_HB_p,
      inout    [21: 0]   FMCP_HB_n,
      inout    [33: 0]   FMCP_LA_p,
      inout    [33: 0]   FMCP_LA_n,
      input    [ 1: 0]   FMCP_CLK_M2C_p,
      input    [ 2: 0]   FMCP_GBTCLK_M2C_p,
      output             FMCP_REFCLK_C2M_p,
      input              FMCP_REFCLK_M2C_p,
      input    [ 2: 0]   FMCP_REFCLK_p,
      input              FMCP_RES0,
      inout              FMCP_SCL,
      inout              FMCP_SDA,
      output             FMCP_SYNC_C2M_p,
      input              FMCP_SYNC_M2C_p,
`endif /*ENABLE_FMCP*/

`ifdef ENABLE_PCIE
      ///////// PCIE /////////
      output   [ 3: 0]   PCIE_TX_p,
      output   [ 3: 0]   PCIE_TX_n,
      input    [ 3: 0]   PCIE_RX_p,
      input    [ 3: 0]   PCIE_RX_n,
      input              PCIE_OB_REFCLK_p,
      input              PCIE_REFCLK_p,
      input              PCIE_PERST_n,
      output             PCIE_WAKE_n,
`endif /*ENABLE_PCIE*/

`ifdef ENABLE_QSFP
      ///////// QSFP /////////
      output   [ 3: 0]   QSFP_TX_p,
      output   [ 3: 0]   QSFP_TX_n,
      input    [ 3: 0]   QSFP_RX_p,
      input    [ 3: 0]   QSFP_RX_n,
      input              CIPRI_REFCLK_p,
      input              QSFP_REFCLK_p,
      input              QSFP_INTERRUPT_n,
      output             QSFP_LP_MODE,
      input              QSFP_MOD_PRS_n,
      output             QSFP_MOD_SEL_n,
      output             QSFP_RST_n,
      inout              QSFP_SCL,
      inout              QSFP_SDA,
`endif /*ENABLE_QSFP*/

      ///////// CAM /////////
      input              CAM_RZQ,

`ifdef ENABLE_CAM1
      ///////// CAM1 /////////
      input              CAM1_CLK_p,
      input              CAM1_CLK_n,
      input    [ 1: 0]   CAM1_D_p,
      input    [ 1: 0]   CAM1_D_n,
      inout              CAM1_I2C_SCL,
      inout              CAM1_I2C_SDA,
      inout              CAM1_GPIO,
`endif /*ENABLE_CAM1*/

`ifdef ENABLE_CAM2
      ///////// CAM2 /////////
      input              CAM2_CLK_p,
      input              CAM2_CLK_n,
      input    [ 1: 0]   CAM2_D_p,
      input    [ 1: 0]   CAM2_D_n,
      inout              CAM2_I2C_SCL,
      inout              CAM2_I2C_SDA,
      inout              CAM2_GPIO,
`endif /*ENABLE_CAM2*/

`ifdef ENABLE_HPS
      ///////// HPS /////////
      output             HPS_ENET_MDC,
      inout              HPS_ENET_MDIO,
      input              HPS_ENET_RX_CLK,
      input              HPS_ENET_RX_CTL,
      input    [ 3: 0]   HPS_ENET_RX_DATA,
      output             HPS_ENET_TX_CLK,
      output             HPS_ENET_TX_CTL,
      output   [ 3: 0]   HPS_ENET_TX_DATA,
      inout    [ 4: 0]   HPS_GPIO,
      inout              HPS_I2C_SCL,
      inout              HPS_I2C_SDA,
      inout              HPS_KEY,
      inout              HPS_LED,
      input              HPS_OSC_CLK,
      output             HPS_SDMMC_CLK,
      inout              HPS_SDMMC_CMD,
//      inout    [ 7: 0]   HPS_SDMMC_DATA,
      inout    [ 3: 0]   HPS_SDMMC_DATA,
      input              HPS_UART_RX,
      output             HPS_UART_TX,
      input              HPS_USB3_REFCLK_100M_p,
      input              HPS_USB3_SS_RX_n,
      input              HPS_USB3_SS_RX_p,
      output             HPS_USB3_SS_TX_n,
      output             HPS_USB3_SS_TX_p,
      input              HPS_USB_CLK,
      inout    [ 7: 0]   HPS_USB_DATA,
      input              HPS_USB_DIR,
      input              HPS_USB_ID,
      input              HPS_USB_NXT,
      output             HPS_USB_STP,
      output             HPS_USB_VBUS_CTRL,
      input              HPS_USB_VBUS_DET,
      input              HPS_USB_VBUS_FLT_n,
`endif /*ENABLE_HPS*/

      ///////// INFO /////////
      output             INFO_SPI_SCLK,
      input              INFO_SPI_MISO,
      output             INFO_SPI_MOSI,
      output             INFO_SPI_CS_n

);


//=======================================================
//  REG/WIRE declarations
//=======================================================

assign SI5340B_OE_n = 1'bZ;
assign SI5340B_RST_n = 1'bZ;
assign SI5391B_OE_n = 1'bZ;
assign SI5391B_RST_n = 1'bZ;




//=======================================================
//  Structural coding
//=======================================================

wire                   system_clk_100;
wire                   system_clk_100_internal;
wire                   ninit_done;
wire                   fpga_reset_n_debounced_wire;
reg                    fpga_reset_n_debounced;
wire                   system_reset_n;
//wire                 h2f_reset;

assign                 system_reset_n = fpga_reset_n_debounced & ~ninit_done;

//assign               system_reset_n = fpga_reset_n_debounced & ~h2f_reset & ~ninit_done;

assign                 system_clk_100   = CLK_100_B2B_p;

assign                 system_clk_100_internal  = system_clk_100;

wire [4-1:0]           fpga_led_pio;
wire [4-1:0]           fpga_dipsw_pio;
wire [4-1:0]           fpga_button_pio;
wire                   fpga_reset_n;
assign                 LED = fpga_led_pio;
assign                 fpga_dipsw_pio = SW;
assign                 fpga_button_pio = BUTTON;
assign                 fpga_reset_n = CPU_RESET_n;

wire [4-1:0]           fpga_debounced_buttons;
wire [4-2:0]           fpga_led_internal;
wire                   heartbeat_led;
reg  [24:0]            heartbeat_count;
assign                 heartbeat_led = ~heartbeat_count[24];
assign                 fpga_led_pio = {heartbeat_led,fpga_led_internal};



// Todo no longer needed
//wire [31:0]            f2h_irq1_irq;
wire                   o_pma_cpu_clk;
wire                   dummy_usb_ctrl;

// Todo no longer needed
//assign                 f2h_irq1_irq    = {32'b0};

// Qsys Top module
qsys_top soc_inst (
.clk_100_clk                               (system_clk_100_internal),
.ninit_done_ninit_done                     (ninit_done),
.led_pio_external_connection_in_port       (fpga_led_internal),
.led_pio_external_connection_out_port      (fpga_led_internal),
.dipsw_pio_external_connection_export      (fpga_dipsw_pio),
.button_pio_external_connection_export     (fpga_debounced_buttons),

.emif_hps_emif_mem_0_mem_ck_t              (DDR4A_CK),
.emif_hps_emif_mem_0_mem_ck_c              (DDR4A_CK_n),
.emif_hps_emif_mem_0_mem_a                 (DDR4A_A),
.emif_hps_emif_mem_0_mem_act_n             (DDR4A_ACT_n),
.emif_hps_emif_mem_0_mem_ba                (DDR4A_BA),
.emif_hps_emif_mem_0_mem_bg                (DDR4A_BG),
.emif_hps_emif_mem_0_mem_cke               (DDR4A_CKE),
.emif_hps_emif_mem_0_mem_cs_n              (DDR4A_CS_n),
.emif_hps_emif_mem_0_mem_odt               (DDR4A_ODT),
.emif_hps_emif_mem_0_mem_reset_n           (DDR4A_RESET_n),
.emif_hps_emif_mem_0_mem_par               (DDR4A_PAR),
.emif_hps_emif_mem_0_mem_alert_n           (DDR4A_ALERT_n),
.emif_hps_emif_mem_0_mem_dqs_t             (DDR4A_DQS),
.emif_hps_emif_mem_0_mem_dqs_c             (DDR4A_DQS_n),
.emif_hps_emif_mem_0_mem_dbi_n             (DDR4A_DBI_n),
.emif_hps_emif_mem_0_mem_dq                (DDR4A_DQ),
.emif_hps_emif_oct_0_oct_rzqin             (DDR4A_RZQ),
.emif_hps_emif_ref_clk_0_clk               (DDR4A_REFCLK_p),
.hps_io_emac2_tx_clk                       (HPS_ENET_TX_CLK),
.hps_io_emac2_rx_clk                       (HPS_ENET_RX_CLK),
.hps_io_emac2_tx_ctl                       (HPS_ENET_TX_CTL),
.hps_io_emac2_rx_ctl                       (HPS_ENET_RX_CTL),
.hps_io_emac2_txd0                         (HPS_ENET_TX_DATA[0]),
.hps_io_emac2_txd1                         (HPS_ENET_TX_DATA[1]),
.hps_io_emac2_rxd0                         (HPS_ENET_RX_DATA[0]),
.hps_io_emac2_rxd1                         (HPS_ENET_RX_DATA[1]),
.hps_io_emac2_txd2                         (HPS_ENET_TX_DATA[2]),
.hps_io_emac2_txd3                         (HPS_ENET_TX_DATA[3]),
.hps_io_emac2_rxd2                         (HPS_ENET_RX_DATA[2]),
.hps_io_emac2_rxd3                         (HPS_ENET_RX_DATA[3]),
.hps_io_mdio2_mdio                         (HPS_ENET_MDIO),
.hps_io_mdio2_mdc                          (HPS_ENET_MDC),
.hps_io_sdmmc_cclk                         (HPS_SDMMC_CLK),
.hps_io_sdmmc_cmd                          (HPS_SDMMC_CMD),
.hps_io_sdmmc_data0                        (HPS_SDMMC_DATA[0]),
.hps_io_sdmmc_data1                        (HPS_SDMMC_DATA[1]),
.hps_io_sdmmc_data2                        (HPS_SDMMC_DATA[2]),
.hps_io_sdmmc_data3                        (HPS_SDMMC_DATA[3]),
//.hps_io_sdmmc_data4                        (HPS_SDMMC_DATA[4]),
//.hps_io_sdmmc_data5                        (HPS_SDMMC_DATA[5]),
//.hps_io_sdmmc_data6                        (HPS_SDMMC_DATA[6]),
//.hps_io_sdmmc_data7                        (HPS_SDMMC_DATA[7]),
.hps_io_i2c0_sda                           (HPS_I2C_SDA),
.hps_io_i2c0_scl                           (HPS_I2C_SCL),
.hps_io_uart0_rx                           (HPS_UART_RX),
.hps_io_uart0_tx                           (HPS_UART_TX),
.usb31_io_vbus_det                         (HPS_USB_VBUS_DET),
.usb31_io_flt_bar                          (HPS_USB_VBUS_FLT_n),
.usb31_io_usb_ctrl                         ({HPS_USB_VBUS_CTRL, dummy_usb_ctrl}),
.usb31_io_usb31_id                         (HPS_USB_ID),
.usb31_phy_refclk_p_clk                    (HPS_USB3_REFCLK_100M_p),
//.usb31_phy_refclk_n_clk                    (HPS_USB3_REFCLK_100M_n),
.usb31_phy_rx_serial_n_i_rx_serial_n       (HPS_USB3_SS_RX_n),
.usb31_phy_rx_serial_p_i_rx_serial_p       (HPS_USB3_SS_RX_p),
.usb31_phy_tx_serial_n_o_tx_serial_n       (HPS_USB3_SS_TX_n),
.usb31_phy_tx_serial_p_o_tx_serial_p       (HPS_USB3_SS_TX_p),
.usb31_phy_pma_cpu_clk_clk                 (o_pma_cpu_clk),
.o_pma_cu_clk_clk                          (o_pma_cpu_clk),
.hps_io_usb1_clk                           (HPS_USB_CLK),
.hps_io_usb1_stp                           (HPS_USB_STP),
.hps_io_usb1_dir                           (HPS_USB_DIR),
// Todo clarify for NXT or NXR
.hps_io_usb1_nxt                           (HPS_USB_NXT),
.hps_io_usb1_data0                         (HPS_USB_DATA[0]),
.hps_io_usb1_data1                         (HPS_USB_DATA[1]),
.hps_io_usb1_data2                         (HPS_USB_DATA[2]),
.hps_io_usb1_data3                         (HPS_USB_DATA[3]),
.hps_io_usb1_data4                         (HPS_USB_DATA[4]),
.hps_io_usb1_data5                         (HPS_USB_DATA[5]),
.hps_io_usb1_data6                         (HPS_USB_DATA[6]),
.hps_io_usb1_data7                         (HPS_USB_DATA[7]),
.hps_io_gpio0                              (HPS_LED),
.hps_io_gpio1                              (HPS_GPIO[0]),
.hps_io_gpio8                              (HPS_GPIO[2]),
.hps_io_gpio9                              (HPS_GPIO[3]),
.hps_io_gpio10                             (HPS_GPIO[1]),
.hps_io_gpio11                             (HPS_GPIO[4]),
.hps_io_gpio28                             (HPS_KEY),
// Todo nolonger export to top
//.f2h_irq1_irq                              (f2h_irq1_irq),
.hps_io_hps_osc_clk                        (HPS_OSC_CLK),

//.h2f_reset_reset                           (h2f_reset),

.reset_reset_n                             (system_reset_n)
);

// debounce fpga_reset_n
debounce fpga_reset_n_debounce_inst (
.clk                                       (system_clk_100_internal),
.reset_n                                   (~ninit_done),
.data_in                                   (fpga_reset_n),
.data_out                                  (fpga_reset_n_debounced_wire)
);
defparam fpga_reset_n_debounce_inst.WIDTH = 1;
defparam fpga_reset_n_debounce_inst.POLARITY = "LOW";
defparam fpga_reset_n_debounce_inst.TIMEOUT = 10000;               // at 100Mhz this is a debounce time of 1ms
defparam fpga_reset_n_debounce_inst.TIMEOUT_WIDTH = 32;            // ceil(log2(TIMEOUT))

always @ (posedge system_clk_100_internal or posedge ninit_done)
begin
    if (ninit_done == 1'b1)
        fpga_reset_n_debounced <= 1'b0;
    else
        fpga_reset_n_debounced <= fpga_reset_n_debounced_wire;
end

// Debounce logic to clean out glitches within 1ms
debounce debounce_inst (
.clk                                       (system_clk_100_internal),
.reset_n                                   (system_reset_n),
.data_in                                   (fpga_button_pio),
.data_out                                  (fpga_debounced_buttons)
);
defparam debounce_inst.WIDTH = 4;
defparam debounce_inst.POLARITY = "LOW";
defparam debounce_inst.TIMEOUT = 10000;               // at 100Mhz this is a debounce time of 1ms
defparam debounce_inst.TIMEOUT_WIDTH = 32;            // ceil(log2(TIMEOUT))

always @(posedge system_clk_100_internal or negedge system_reset_n) begin
  if (~system_reset_n)
    heartbeat_count <= 25'd0;
  else
    heartbeat_count <= heartbeat_count + 25'd1;
end

endmodule
