////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2013-2023 Efinix Inc. All rights reserved.              
//
// This   document  contains  proprietary information  which   is        
// protected by  copyright. All rights  are reserved.  This notice       
// refers to original work by Efinix, Inc. which may be derivitive       
// of other work distributed under license of the authors.  In the       
// case of derivative work, nothing in this notice overrides the         
// original author's license agreement.  Where applicable, the           
// original license agreement is included in it's original               
// unmodified form immediately below this header.                        
//                                                                       
// WARRANTY DISCLAIMER.                                                  
//     THE  DESIGN, CODE, OR INFORMATION ARE PROVIDED “AS IS” AND        
//     EFINIX MAKES NO WARRANTIES, EXPRESS OR IMPLIED WITH               
//     RESPECT THERETO, AND EXPRESSLY DISCLAIMS ANY IMPLIED WARRANTIES,  
//     INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF          
//     MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR    
//     PURPOSE.  SOME STATES DO NOT ALLOW EXCLUSIONS OF AN IMPLIED       
//     WARRANTY, SO THIS DISCLAIMER MAY NOT APPLY TO LICENSEE.           
//                                                                       
// LIMITATION OF LIABILITY.                                              
//     NOTWITHSTANDING ANYTHING TO THE CONTRARY, EXCEPT FOR BODILY       
//     INJURY, EFINIX SHALL NOT BE LIABLE WITH RESPECT TO ANY SUBJECT    
//     MATTER OF THIS AGREEMENT UNDER TORT, CONTRACT, STRICT LIABILITY   
//     OR ANY OTHER LEGAL OR EQUITABLE THEORY (I) FOR ANY INDIRECT,      
//     SPECIAL, INCIDENTAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES OF ANY    
//     CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF      
//     GOODWILL, DATA OR PROFIT, WORK STOPPAGE, OR COMPUTER FAILURE OR   
//     MALFUNCTION, OR IN ANY EVENT (II) FOR ANY AMOUNT IN EXCESS, IN    
//     THE AGGREGATE, OF THE FEE PAID BY LICENSEE TO EFINIX HEREUNDER    
//     (OR, IF THE FEE HAS BEEN WAIVED, $100), EVEN IF EFINIX SHALL HAVE 
//     BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES.  SOME STATES DO 
//     NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR            
//     CONSEQUENTIAL DAMAGES, SO THIS LIMITATION AND EXCLUSION MAY NOT   
//     APPLY TO LICENSEE.                                                
//
////////////////////////////////////////////////////////////////////////////////

module core #(
    parameter MEM_DW = 512,
    parameter AXIS_DW = 64
) (
    input                   io_systemReset,
    input                   io_ddrMasterReset,
    input                   io_peripheralClk,
    input                   io_memoryClk,
    input                   io_tseClk,

    output          [3:0]   rgmii_txd_HI,
    output          [3:0]   rgmii_txd_LO,
    output                  rgmii_tx_ctl_HI,
    output                  rgmii_tx_ctl_LO,
    output                  rgmii_txc_HI,
    output                  rgmii_txc_LO,
    input           [3:0]   rgmii_rxd_HI,
    input           [3:0]   rgmii_rxd_LO,
    input                   rgmii_rx_ctl_HI,
    input                   rgmii_rx_ctl_LO,
    input                   rgmii_rxc,
    //TEMAC PHY MDIO Interface
    input                   phy_mdi,
    output                  phy_mdo,
    output                  phy_mdo_en,
    output                  phy_mdc,

    //DMA
    input                   dmaaxi_read_arready,
    input                   dmaaxi_read_rvalid,
    input    [AXIS_DW-1:0]  dmaaxi_read_rdata,
    input    [1:0]          dmaaxi_read_rresp,
    input                   dmaaxi_read_rlast,
    input                   dmaaxi_write_awready,
    input                   dmaaxi_write_wready,
    input                   dmaaxi_write_bvalid,
    input    [1:0]          dmaaxi_write_bresp,
    output                  dmaaxi_read_arvalid,
    output   [31:0]         dmaaxi_read_araddr,
    output   [3:0]          dmaaxi_read_arregion,
    output   [7:0]          dmaaxi_read_arlen,
    output   [2:0]          dmaaxi_read_arsize,
    output   [1:0]          dmaaxi_read_arburst,
    output   [0:0]          dmaaxi_read_arlock,
    output   [3:0]          dmaaxi_read_arcache,
    output   [3:0]          dmaaxi_read_arqos,
    output   [2:0]          dmaaxi_read_arprot,
    output                  dmaaxi_read_rready,
    output                  dmaaxi_write_awvalid,
    output   [31:0]         dmaaxi_write_awaddr,
    output   [3:0]          dmaaxi_write_awregion,
    output   [7:0]          dmaaxi_write_awlen,
    output   [2:0]          dmaaxi_write_awsize,
    output   [1:0]          dmaaxi_write_awburst,
    output   [0:0]          dmaaxi_write_awlock,
    output   [3:0]          dmaaxi_write_awcache,
    output   [3:0]          dmaaxi_write_awqos,
    output   [2:0]          dmaaxi_write_awprot,
    output                  dmaaxi_write_wvalid,
    output   [AXIS_DW-1:0]  dmaaxi_write_wdata,
    output   [AXIS_DW/8-1:0]dmaaxi_write_wstrb,
    output                  dmaaxi_write_wlast,
    output                  dmaaxi_write_bready,

    input    [31:0]         dma_apb3_paddr,
    input                   dma_apb3_psel,
    input                   dma_apb3_penable,
    output                  dma_apb3_pready,
    input                   dma_apb3_pwrite,
    input    [31:0]         dma_apb3_pwdata,
    output   [31:0]         dma_apb3_prdata,
    output                  dma_apb3_pslverror,
    //Mac APB3 Interface
    input    [31:0]         eth_apb3_paddr,
    input                   eth_apb3_psel,
    input                   eth_apb3_penable,
    output                  eth_apb3_pready,
    input                   eth_apb3_pwrite,
    input    [31:0]         eth_apb3_pwdata,
    output    [31:0]        eth_apb3_prdata,
    output                  eth_apb3_pslverror,

    input                   pll_locked,
    output                  phy_sw_rst,
    output [1:0]            dma_interrupts,
    output  [2:0]           eth_speed
);

wire            s_eth_tx_tvalid;
wire            s_eth_tx_tready;
wire    [7:0]   s_eth_tx_tdata;
wire    [0:0]   s_eth_tx_tkeep;
wire    [3:0]   s_eth_tx_tdest;
wire            s_eth_tx_tlast;
wire            m_eth_tx_tvalid;
wire            m_eth_tx_tready;
wire    [7:0]   m_eth_tx_tdata;
wire    [3:0]   m_eth_tx_tdest;
wire            m_eth_tx_tlast;

wire            s_eth_rx_tvalid;
wire            s_eth_rx_tready;
wire    [7:0]   s_eth_rx_tdata;
wire    [0:0]   s_eth_rx_tstrb;

wire            s_eth_rx_tlast;
wire            s_eth_rx_tuser;
wire            m_eth_rx_tvalid;
wire            m_eth_rx_tready;
wire    [7:0]   m_eth_rx_tdata;
wire    [0:0]   m_eth_rx_tkeep;
wire    [3:0]   m_eth_rx_tdest;
wire            m_eth_rx_tlast;

//Mac APB3 Interface
wire    [9:0]   mac_apb3_paddr;
wire            mac_apb3_psel;
wire            mac_apb3_penable;
wire            mac_apb3_pready;
wire            mac_apb3_pwrite;
wire    [31:0]  mac_apb3_pwdata;
wire    [31:0]  mac_apb3_prdata;
wire            mac_apb3_pslverror;
//Common APB3 Interface
wire    [8:0]   cmn_apb3_paddr;
wire            cmn_apb3_psel;
wire            cmn_apb3_penable;
wire            cmn_apb3_pready;
wire            cmn_apb3_pwrite;
wire    [31:0]  cmn_apb3_pwdata;
wire    [31:0]  cmn_apb3_prdata;
wire            cmn_apb3_pslverror;

wire            io_0_descriptorUpdate;
wire            io_1_descriptorUpdate;
wire            mac_sw_rst;
wire            dma_rx_rst;
wire            dma_tx_rst;
wire            tse_mac_rst;
wire            rx_axis_clk;
wire            tx_axis_clk;
wire            proto_reset;
wire            tse_mac_srst;

//tse
wire    [9:0]   axil_awaddr;
wire            axil_awvalid;
wire            axil_awready;
wire    [31:0]  axil_wdata;
wire            axil_wvalid;
wire            axil_wready;
wire    [1:0]   axil_bresp;
wire            axil_bvalid;
wire            axil_bready;
wire    [9:0]   axil_araddr;
wire            axil_arvalid;
wire            axil_arready;
wire    [1:0]   axil_rresp;
wire    [31:0]  axil_rdata;
wire            axil_rvalid;
wire            axil_rready;

assign mac_apb3_paddr   = {1'b0, eth_apb3_paddr[0 +: 9]};
assign mac_apb3_psel    = (eth_apb3_paddr[9] == 1'b0) ? eth_apb3_psel : 1'b0;
assign mac_apb3_penable = eth_apb3_penable;
assign mac_apb3_pwrite  = eth_apb3_pwrite;
assign mac_apb3_pwdata  = eth_apb3_pwdata;

assign cmn_apb3_paddr   = eth_apb3_paddr[0 +: 9];
assign cmn_apb3_psel    = (eth_apb3_paddr[9] == 1'b1) ? eth_apb3_psel : 1'b0;
assign cmn_apb3_penable = eth_apb3_penable;
assign cmn_apb3_pwrite  = eth_apb3_pwrite;
assign cmn_apb3_pwdata  = eth_apb3_pwdata;

assign eth_apb3_pready    = (eth_apb3_paddr[9] == 1'b0) ? mac_apb3_pready    : cmn_apb3_pready;
assign eth_apb3_prdata    = (eth_apb3_paddr[9] == 1'b0) ? mac_apb3_prdata    : cmn_apb3_prdata;
assign eth_apb3_pslverror = (eth_apb3_paddr[9] == 1'b0) ? mac_apb3_pslverror : cmn_apb3_pslverror;
//TSE
assign rx_axis_clk = io_tseClk;
assign tx_axis_clk = io_tseClk;

assign tse_mac_rst  = ~pll_locked;

reset_ctrl #(
    .NUM_RST(2),
    .CYCLE(2),
    .IN_RST_ACTIVE(2'b11),
    .OUT_RST_ACTIVE(2'b11)
) inst_reset_ctrl (
    .i_arst({mac_sw_rst, tse_mac_rst}),
    .i_clk({2{tx_axis_clk}}),
    .o_srst({proto_reset, tse_mac_srst})
);


dma u_dma (
    .clk                  (io_memoryClk),
    .reset                (io_ddrMasterReset),
    .ctrl_clk             (io_peripheralClk),
    .ctrl_reset           (io_systemReset),
    .ctrl_PADDR           (dma_apb3_paddr),
    .ctrl_PREADY          (dma_apb3_pready),
    .ctrl_PENABLE         (dma_apb3_penable),
    .ctrl_PSEL            (dma_apb3_psel),
    .ctrl_PWRITE          (dma_apb3_pwrite),
    .ctrl_PWDATA          (dma_apb3_pwdata),
    .ctrl_PRDATA          (dma_apb3_prdata),
    .ctrl_PSLVERROR       (dma_apb3_pslverror),
    .ctrl_interrupts      (dma_interrupts),
    .read_arvalid         (dmaaxi_read_arvalid),
    .read_araddr          (dmaaxi_read_araddr),
    .read_arready         (dmaaxi_read_arready),
    .read_arregion        (dmaaxi_read_arregion),
    .read_arlen           (dmaaxi_read_arlen),
    .read_arsize          (dmaaxi_read_arsize),
    .read_arburst         (dmaaxi_read_arburst),
    .read_arlock          (dmaaxi_read_arlock),
    .read_arcache         (dmaaxi_read_arcache),
    .read_arqos           (dmaaxi_read_arqos),
    .read_arprot          (dmaaxi_read_arprot),
    .read_rready          (dmaaxi_read_rready),
    .read_rvalid          (dmaaxi_read_rvalid),
    .read_rdata           (dmaaxi_read_rdata),
    .read_rlast           (dmaaxi_read_rlast),
    .read_rresp           (dmaaxi_read_rresp),
    .write_awvalid        (dmaaxi_write_awvalid),
    .write_awready        (dmaaxi_write_awready),
    .write_awaddr         (dmaaxi_write_awaddr),
    .write_awregion       (dmaaxi_write_awregion),
    .write_awlen          (dmaaxi_write_awlen),
    .write_awsize         (dmaaxi_write_awsize),
    .write_awburst        (dmaaxi_write_awburst),
    .write_awlock         (dmaaxi_write_awlock),
    .write_awcache        (dmaaxi_write_awcache),
    .write_awqos          (dmaaxi_write_awqos),
    .write_awprot         (dmaaxi_write_awprot),
    .write_wvalid         (dmaaxi_write_wvalid),
    .write_wready         (dmaaxi_write_wready),
    .write_wdata          (dmaaxi_write_wdata),
    .write_wstrb          (dmaaxi_write_wstrb),
    .write_wlast          (dmaaxi_write_wlast),
    .write_bvalid         (dmaaxi_write_bvalid),
    .write_bready         (dmaaxi_write_bready),
    .write_bresp          (dmaaxi_write_bresp),
    .io_1_descriptorUpdate(io_1_descriptorUpdate),
    .dat1_o_clk           (tx_axis_clk),
    .dat1_o_reset         (tse_mac_rst | dma_tx_rst),
    .dat1_o_tvalid        (s_eth_tx_tvalid),
    .dat1_o_tready        (s_eth_tx_tready),
    .dat1_o_tdata         (s_eth_tx_tdata),
    .dat1_o_tkeep         (s_eth_tx_tkeep),
    .dat1_o_tdest         (s_eth_tx_tdest),
    .dat1_o_tlast         (s_eth_tx_tlast),
    .io_0_descriptorUpdate(io_0_descriptorUpdate),
    .dat0_i_clk           (rgmii_rxc),
    .dat0_i_reset         (tse_mac_rst | dma_rx_rst),
    .dat0_i_tvalid        (m_eth_rx_tvalid),
    .dat0_i_tready        (m_eth_rx_tready),
    .dat0_i_tdata         (m_eth_rx_tdata),
    .dat0_i_tkeep         (1'b1),
    .dat0_i_tdest         (m_eth_rx_tdest),
    .dat0_i_tlast         (m_eth_rx_tlast)
);

assign axil_bready = 1'b1;
apb3_2_axi4_lite u_apb3_2_axi4_lite
(
//Globle Signals
    .clk                        (io_peripheralClk                   ),
    .rstn                       (~(io_systemReset || mac_sw_rst)),
//APB3 Slave Interface
    .s_apb3_paddr               (mac_apb3_paddr             ),
    .s_apb3_psel                (mac_apb3_psel              ),
    .s_apb3_penable             (mac_apb3_penable           ),
    .s_apb3_pready              (mac_apb3_pready            ),
    .s_apb3_pwrite              (mac_apb3_pwrite            ),
    .s_apb3_pwdata              (mac_apb3_pwdata            ),
    .s_apb3_prdata              (mac_apb3_prdata            ),
    .s_apb3_pslverror           (mac_apb3_pslverror         ),
//AXI4-Lite Master Interface
    .m_axi_awaddr               (axil_awaddr                ),
    .m_axi_awvalid              (axil_awvalid               ),
    .m_axi_awready              (axil_awready               ),
    .m_axi_wdata                (axil_wdata                 ),
    .m_axi_wvalid               (axil_wvalid                ),
    .m_axi_wready               (axil_wready                ),
    .m_axi_araddr               (axil_araddr                ),
    .m_axi_arvalid              (axil_arvalid               ),
    .m_axi_arready              (axil_arready               ),
    .m_axi_rdata                (axil_rdata                 ),
    .m_axi_rvalid               (axil_rvalid                ),
    .m_axi_rready               (axil_rready                )
);


assign m_eth_rx_tvalid = s_eth_rx_tvalid;
assign m_eth_rx_tdata = s_eth_rx_tdata;
assign m_eth_rx_tkeep = 1;
assign m_eth_rx_tlast = s_eth_rx_tlast;
assign s_eth_rx_tready = m_eth_rx_tready;
ethernet_ctrl #(
    .ADDR_WIDTH(9),
    .DATA_WIDTH(32)
) u_ethernet_ctrl (
    .s_apb3_clk      (io_peripheralClk),
    .s_apb3_rstn     (~io_systemReset),
    .s_apb3_paddr    (cmn_apb3_paddr),
    .s_apb3_psel     (cmn_apb3_psel),
    .s_apb3_penable  (cmn_apb3_penable),
    .s_apb3_pwrite   (cmn_apb3_pwrite),
    .s_apb3_pwdata   (cmn_apb3_pwdata),
    .s_apb3_pready   (cmn_apb3_pready),
    .s_apb3_prdata   (cmn_apb3_prdata),
    .s_apb3_pslverror(cmn_apb3_pslverror),

    .eth_mac_rst    (tse_mac_rst || mac_sw_rst),
    .s_eth_tx_clk   (tx_axis_clk),
    .s_eth_tx_tvalid(s_eth_tx_tvalid),
    .s_eth_tx_tready(s_eth_tx_tready),
    .s_eth_tx_tdata (s_eth_tx_tdata),
    .s_eth_tx_tkeep (s_eth_tx_tkeep),
    .s_eth_tx_tdest (s_eth_tx_tdest),
    .s_eth_tx_tlast (s_eth_tx_tlast),
    .m_eth_tx_clk   (tx_axis_clk),
    .m_eth_tx_tvalid(m_eth_tx_tvalid),
    .m_eth_tx_tready(m_eth_tx_tready),
    .m_eth_tx_tdata (m_eth_tx_tdata),
    .m_eth_tx_tdest (m_eth_tx_tdest),
    .m_eth_tx_tlast (m_eth_tx_tlast),

    .mac_sw_rst             (mac_sw_rst),
    .phy_sw_rst             (phy_sw_rst),
    .dma_rx_rst             (dma_rx_rst),
    .dma_tx_rst             (dma_tx_rst),
    .dma_descriptor_update  (io_0_descriptorUpdate)
);

efx_tsemac u_efx_tsemac (
    .mac_reset                  (tse_mac_srst),
    .proto_reset                (tse_mac_srst || proto_reset),
    .tx_mac_aclk                (io_tseClk),
    .rx_mac_aclk                (),
    .eth_speed                  (eth_speed  ),

    ////----    RX AXI-Stream     ----////
    .rx_axis_clk                (rgmii_rxc            ),
    .rx_axis_mac_tdata          (s_eth_rx_tdata         ),
    .rx_axis_mac_tvalid         (s_eth_rx_tvalid        ),
    .rx_axis_mac_tstrb          (s_eth_rx_tstrb),
    .rx_axis_mac_tlast          (s_eth_rx_tlast         ),
    .rx_axis_mac_tuser          (s_eth_rx_tuser         ),
    .rx_axis_mac_tready         (s_eth_rx_tready        ),

    ////----    TX AXI-Stream     ----////
    .tx_axis_clk                (tx_axis_clk                ),
    .tx_axis_mac_tdata          (m_eth_tx_tdata                ),
    .tx_axis_mac_tvalid         (m_eth_tx_tvalid),
    .tx_axis_mac_tstrb          (1),
    .tx_axis_mac_tlast          (m_eth_tx_tlast                ),
    .tx_axis_mac_tuser          (1'b0                       ),
    .tx_axis_mac_tready         (m_eth_tx_tready               ),

    ////----    AXI4-Lite Interface     ----////
    .s_axi_aclk                 (io_peripheralClk               ),
    .s_axi_awaddr               (axil_awaddr                ),
    .s_axi_awvalid              (axil_awvalid               ),
    .s_axi_awready              (axil_awready               ),
    .s_axi_wdata                (axil_wdata                 ),
    .s_axi_wvalid               (axil_wvalid                ),
    .s_axi_wready               (axil_wready                ),
    .s_axi_bresp                (axil_bresp                 ),
    .s_axi_bvalid               (axil_bvalid                ),
    .s_axi_bready               (axil_bready                ),
    .s_axi_araddr               (axil_araddr                ),
    .s_axi_arvalid              (axil_arvalid               ),
    .s_axi_arready              (axil_arready               ),
    .s_axi_rresp                (axil_rresp                 ),
    .s_axi_rdata                (axil_rdata                 ),
    .s_axi_rvalid               (axil_rvalid                ),
    .s_axi_rready               (axil_rready                ),

    ////----    RGMII interface     ----////
    .rgmii_txd_HI               (rgmii_txd_HI),
    .rgmii_txd_LO               (rgmii_txd_LO),
    .rgmii_tx_ctl_HI            (rgmii_tx_ctl_HI),
    .rgmii_tx_ctl_LO            (rgmii_tx_ctl_LO),
    .rgmii_txc_HI               (rgmii_txc_HI),
    .rgmii_txc_LO               (rgmii_txc_LO),
    .rgmii_rxd_HI               (rgmii_rxd_HI),
    .rgmii_rxd_LO               (rgmii_rxd_LO),
    .rgmii_rx_ctl_HI            (rgmii_rx_ctl_HI),
    .rgmii_rx_ctl_LO            (rgmii_rx_ctl_LO),
    .rgmii_rxc                  (rgmii_rxc),

    ////----    MDIO Interface      ----////
    .Mdo                        (phy_mdo                    ),
    .MdoEn                      (phy_mdo_en                 ),
    .Mdi                        (phy_mdi                    ),
    .Mdc                        (phy_mdc                    )
);

wire            tx_interrupt;
wire            rx_interrupt;
assign rx_interrupt = dma_interrupts[0];
assign tx_interrupt = dma_interrupts[1];
reg [31:0] tx_latency = 0;
reg [31:0] rx_latency = 0;
reg last_rx_interrupt = 0;
reg last_tx_interrupt = 0;
integer tse_tx_cnt = 0;

always @(posedge io_peripheralClk) begin
    last_rx_interrupt <= rx_interrupt;
    if (!last_rx_interrupt && rx_interrupt) begin
        rx_latency <= 0;
    end
    else if (rx_interrupt)
        rx_latency <= rx_latency + 1;
end

always @(posedge io_peripheralClk) begin
    last_tx_interrupt <= tx_interrupt;
    if (!last_tx_interrupt && tx_interrupt) begin
        tx_latency <= 0;
    end
    else if (tx_interrupt)
        tx_latency <= tx_latency + 1;
end

always @(posedge tx_axis_clk or posedge tse_mac_rst) begin
    if (tse_mac_rst) begin
        tse_tx_cnt <= 0;
    end else begin
        if (m_eth_tx_tready && m_eth_tx_tvalid && m_eth_tx_tlast) begin
            tse_tx_cnt <= tse_tx_cnt + 1;
        end
    end
end

endmodule
