-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--
-- Copyright 2025 VLSI Solution Oy
-- SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
--
-- Licensed under the Solderpad Hardware License v 2.1 (the "License");
-- you may not use this file except in compliance with the License, or,
-- at your option, the Apache License version 2.0.
-- You may obtain a copy of the License at
--
--    https://solderpad.org/licenses/SHL-2.1/
--
-- Unless required by applicable law or agreed to in writing, any work
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--                               RISCV core
--                                 V1.1
--
--
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

-- - - - - - - -
--  libraries
-- - - - - - - -
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use work.rv_pkg.all;


entity rv_ddr2_fpga is
  port ( clk_50m_i    : in    std_logic;
         xrst_i       : in    std_logic;
         --
         uart_rxd_o   : out   std_logic;
         uart_txd_i   : in    std_logic;
         uart2_rxd_o  : out   std_logic;
         uart2_txd_i  : in    std_logic;
         --
         spi_miso_i   : in    std_logic;
         spi_clk_o    : out   std_logic;
         spi_mosi_o   : out   std_logic;
         spi_cs_o     : out   std_logic;
         --
         gpio_i       : in    slv_07_00;
         gpio_oena_o  : out   slv_07_00;
         gpio_o       : out   slv_07_00;
          --
         ddr2_cke     : out   slv_00_00;
         ddr2_ck_p    : inout slv_00_00;
         ddr2_ck_n    : inout slv_00_00;
         ddr2_cs_n    : out   slv_00_00;
         ddr2_ras_n   : out   std_logic;
         ddr2_cas_n   : out   std_logic;
         ddr2_we_n    : out   std_logic;
         ddr2_ba      : out   slv_01_00;
         ddr2_addr    : out   slv_12_00;
         ddr2_odt     : out   slv_00_00;
         ddr2_dm      : out   slv_01_00;
         ddr2_dqs_p   : inout slv_00_00;
         ddr2_dqs_n   : inout slv_00_00;
         ddr2_dq      : inout slv_15_00
         );
end entity rv_ddr2_fpga;

architecture rtl of rv_ddr2_fpga is

  component axi_ddr2
    port ( clk_clk                        : in    std_logic := 'X';
           reset_reset_n                  : in    std_logic := 'X';
           ddr2_mem_odt                   : out   slv_00_00;
           ddr2_mem_clk                   : inout slv_00_00 := (others => 'X');
           ddr2_mem_clk_n                 : inout slv_00_00 := (others => 'X');
           ddr2_mem_cs_n                  : out   slv_00_00;
           ddr2_mem_cke                   : out   slv_00_00;
           ddr2_mem_addr                  : out   slv_12_00;
           ddr2_mem_ba                    : out   slv_01_00;
           ddr2_mem_ras_n                 : out   std_logic;
           ddr2_mem_cas_n                 : out   std_logic;
           ddr2_mem_we_n                  : out   std_logic;
           ddr2_mem_dq                    : inout slv_15_00 := (others => 'X');
           ddr2_mem_dqs                   : inout slv_01_00 := (others => 'X');
           ddr2_mem_dm                    : out   slv_01_00;
           axi_trans_s0_awid              : in    slv_03_00 := (others => 'X');
           axi_trans_s0_awaddr            : in    slv_31_00 := (others => 'X');
           axi_trans_s0_awlen             : in    slv_07_00 := (others => 'X');
           axi_trans_s0_awsize            : in    slv_02_00 := (others => 'X');
           axi_trans_s0_awburst           : in    slv_01_00 := (others => 'X');
           axi_trans_s0_awlock            : in    slv_00_00 := (others => 'X');
           axi_trans_s0_awcache           : in    slv_03_00 := (others => 'X');
           axi_trans_s0_awprot            : in    slv_02_00 := (others => 'X');
           axi_trans_s0_awvalid           : in    std_logic := 'X';
           axi_trans_s0_awready           : out   std_logic;
           axi_trans_s0_wdata             : in    slv_31_00 := (others => 'X');
           axi_trans_s0_wstrb             : in    slv_03_00 := (others => 'X');
           axi_trans_s0_wlast             : in    std_logic := 'X';
           axi_trans_s0_wvalid            : in    std_logic := 'X';
           axi_trans_s0_wready            : out   std_logic;
           axi_trans_s0_bid               : out   slv_03_00;
           axi_trans_s0_bresp             : out   slv_01_00;
           axi_trans_s0_bvalid            : out   std_logic;
           axi_trans_s0_bready            : in    std_logic := 'X';
           axi_trans_s0_arid              : in    slv_03_00 := (others => 'X');
           axi_trans_s0_araddr            : in    slv_31_00 := (others => 'X');
           axi_trans_s0_arlen             : in    slv_07_00 := (others => 'X');
           axi_trans_s0_arsize            : in    slv_02_00 := (others => 'X');
           axi_trans_s0_arburst           : in    slv_01_00 := (others => 'X');
           axi_trans_s0_arlock            : in    slv_00_00 := (others => 'X');
           axi_trans_s0_arcache           : in    slv_03_00 := (others => 'X');
           axi_trans_s0_arprot            : in    slv_02_00 := (others => 'X');
           axi_trans_s0_arvalid           : in    std_logic := 'X';
           axi_trans_s0_arready           : out   std_logic;
           axi_trans_s0_rid               : out   slv_03_00;
           axi_trans_s0_rdata             : out   slv_31_00;
           axi_trans_s0_rresp             : out   slv_01_00;
           axi_trans_s0_rlast             : out   std_logic;
           axi_trans_s0_rvalid            : out   std_logic;
           axi_trans_s0_rready            : in    std_logic  := 'X';
           ddr2_ext_local_refresh_ack     : out   std_logic;
           ddr2_ext_local_init_done       : out   std_logic;
           ddr2_ext_reset_phy_clk_n       : out   std_logic;
           ddr2_ext_dll_reference_clk     : out   std_logic;
           ddr2_ext_dqs_delay_ctrl_export : out   slv_05_00;
           ddr2_ext_local_autopch_req     : in    std_logic := 'X';
           ddr2_ext_local_self_rfsh_req   : in    std_logic := 'X';
           ddr2_ext_local_self_rfsh_chip  : in    std_logic := 'X';
           ddr2_ext_local_self_rfsh_ack   : out   std_logic;
           ddr2_auxfull_clk               : out   std_logic;
           ddr2_auxhalf_clk               : out   std_logic
           );
  end component;


  component rv_soc
    generic ( CLK_FREQ    : natural := 50000000;           -- default 50M
              UART_SPEED  : natural :=  1000000;           -- default 1M
              NR_GPIOS    : integer range 1 to 32 := 8 );
    port ( clk_i           : in  std_logic;
           xrst_i          : in  std_logic;
           --
           xmem_awready_i  : in  std_logic;                -- xmem
           xmem_wready_i   : in  std_logic;
           xmem_bvalid_i   : in  std_logic;
           xmem_bresp_i    : in  slv_01_00;
           xmem_bid_i      : in  slv_03_00;
           xmem_arready_i  : in  std_logic;
           xmem_rvalid_i   : in  std_logic;
           xmem_rdata_i    : in  slv_31_00;
           xmem_rresp_i    : in  slv_01_00;
           xmem_rid_i      : in  slv_03_00;
           xmem_rlast_i    : in  std_logic;
           xmem_awvalid_o  : out std_logic;
           xmem_awaddr_o   : out slv_31_00;
           xmem_awid_o     : out slv_03_00;
           xmem_awlen_o    : out slv_07_00;
           xmem_awburst_o  : out slv_01_00;
           xmem_wvalid_o   : out std_logic;
           xmem_wdata_o    : out slv_31_00;
           xmem_wstrb_o    : out slv_03_00;
           xmem_wlast_o    : out std_logic;
           xmem_bready_o   : out std_logic;
           xmem_arvalid_o  : out std_logic;
           xmem_araddr_o   : out slv_31_00;
           xmem_arid_o     : out slv_03_00;
           xmem_arlen_o    : out slv_07_00;
           xmem_arburst_o  : out slv_01_00;
           xmem_rready_o   : out std_logic;
           --
           uart_txd_i      : in  std_logic;                 -- io pins
           uart_rxd_o      : out std_logic;
           uart2_txd_i     : in  std_logic;
           uart2_rxd_o     : out std_logic;
           --
           spi_miso_i      : in  std_logic;
           spi_clk_o       : out std_logic;
           spi_cs_o        : out std_logic;
           spi_mosi_o      : out std_logic;
           --
           gpio_i          : in  slv_t(NR_GPIOS-1 downto 0);
           gpio_oena_o     : out slv_t(NR_GPIOS-1 downto 0);
           gpio_o          : out slv_t(NR_GPIOS-1 downto 0)
           );
  end component;


  signal xrst_sys_w           : std_logic;

  signal axi_rvalid_w         : std_logic;
  signal axi_wlast_w          : std_logic;
  signal axi_rlast_w          : std_logic;
  signal axi_arid_w           : slv_03_00;
  signal axi_rresp_w          : slv_01_00;
  signal axi_wvalid_w         : std_logic;
  signal axi_awlen_w          : slv_07_00;
  signal axi_awburst_w        : slv_01_00;
  signal axi_bresp_w          : slv_01_00;
  signal axi_rdata_w          : slv_31_00;
  signal axi_arready_w        : std_logic;
  signal axi_awvalid_w        : std_logic;
  signal axi_araddr_w         : slv_31_00;
  signal axi_arburst_w        : slv_01_00;
  signal axi_wready_w         : std_logic;
  signal axi_arlen_w          : slv_07_00;
  signal axi_awready_w        : std_logic;
  signal axi_bid_w            : slv_03_00;
  signal axi_wstrb_w          : slv_03_00;
  signal axi_awid_w           : slv_03_00;
  signal axi_rready_w         : std_logic;
  signal axi_rid_w            : slv_03_00;
  signal axi_arvalid_w        : std_logic;
  signal axi_awaddr_w         : slv_31_00;
  signal axi_bvalid_w         : std_logic;
  signal axi_bready_w         : std_logic;
  signal axi_wdata_w          : slv_31_00;

  signal ddr2_init_done       : std_logic;

  signal xrst0_q              : std_logic;
  signal xrst_q               : std_logic;
  
begin

  -- NOTE: DDR2 clock is 150MHz

  axi_ddr2_i0 : axi_ddr2
    port map ( clk_clk                        => clk_50m_i,      -- in
               reset_reset_n                  => xrst_q,         -- in
               ddr2_auxfull_clk               => OPEN,           -- out
               ddr2_auxhalf_clk               => OPEN,           -- out
               -- Inputs (24)
               axi_trans_s0_awvalid           => axi_awvalid_w,  -- in
               axi_trans_s0_awaddr            => axi_awaddr_w,   -- in [31:0]
               axi_trans_s0_awid              => axi_awid_w,     -- in [3:0]
               axi_trans_s0_awlen             => axi_awlen_w,    -- in [7:0]
               axi_trans_s0_awburst           => axi_awburst_w,  -- in [1:0]
               axi_trans_s0_wvalid            => axi_wvalid_w,   -- in
               axi_trans_s0_wdata             => axi_wdata_w,    -- in [31:0]
               axi_trans_s0_wstrb             => axi_wstrb_w,    -- in [3:0]
               axi_trans_s0_wlast             => axi_wlast_w,    -- in
               axi_trans_s0_bready            => axi_bready_w,   -- in
               axi_trans_s0_arvalid           => axi_arvalid_w,  -- in
               axi_trans_s0_araddr            => axi_araddr_w,   -- in [31:0]
               axi_trans_s0_arid              => axi_arid_w,     -- in [3:0]
               axi_trans_s0_arlen             => axi_arlen_w,    -- in [7:0]
               axi_trans_s0_arburst           => axi_arburst_w,  -- in [1:0]
               axi_trans_s0_rready            => axi_rready_w,   -- in
               -- Seems these inputs are NC (optional)
               axi_trans_s0_awsize            => "010",          -- in [2:0]
               axi_trans_s0_awlock            => "0",            -- in [0:0]
               axi_trans_s0_awcache           => "0010",         -- in [3:0]
               axi_trans_s0_awprot            => "010",          -- in [2:0]
               axi_trans_s0_arsize            => "010",          -- in [2:0]
               axi_trans_s0_arlock            => "0",            -- in [0:0]
               axi_trans_s0_arcache           => "0010",         -- in [3:0]
               axi_trans_s0_arprot            => "010",          -- in [2:0]
               -- Outputs (11)
               axi_trans_s0_awready           => axi_awready_w,  -- out
               axi_trans_s0_wready            => axi_wready_w,   -- out
               axi_trans_s0_bvalid            => axi_bvalid_w,   -- out
               axi_trans_s0_bresp             => axi_bresp_w,    -- out [1:0]
               axi_trans_s0_bid               => axi_bid_w,      -- out [3:0]
               axi_trans_s0_arready           => axi_arready_w,  -- out
               axi_trans_s0_rvalid            => axi_rvalid_w,   -- out
               axi_trans_s0_rdata             => axi_rdata_w,    -- out [31:0]
               axi_trans_s0_rresp             => axi_rresp_w,    -- out [1:0]
               axi_trans_s0_rid               => axi_rid_w,      -- out [3:0]
               axi_trans_s0_rlast             => axi_rlast_w,    -- out
               -- DDR2
               ddr2_mem_clk                   => ddr2_ck_p,      -- ino [0:0]
               ddr2_mem_clk_n                 => ddr2_ck_n,      -- ino [0:0]
               ddr2_mem_cke                   => ddr2_cke,       -- out [0:0]
               ddr2_mem_ras_n                 => ddr2_ras_n,     -- out
               ddr2_mem_cas_n                 => ddr2_cas_n,     -- out
               ddr2_mem_we_n                  => ddr2_we_n,      -- out
               ddr2_mem_cs_n                  => ddr2_cs_n,      -- out [0:0]
               ddr2_mem_ba                    => ddr2_ba,        -- out [1:0]
               ddr2_mem_addr                  => ddr2_addr,      -- out [12:0]
               ddr2_mem_odt                   => ddr2_odt,       -- out [0:0]
               ddr2_mem_dm                    => ddr2_dm,        -- out [1:0]
               ddr2_mem_dqs(1)                => ddr2_dqs_n(0),  -- inout [1:0]
               ddr2_mem_dqs(0)                => ddr2_dqs_p(0),  -- inout [1:0]
               ddr2_mem_dq                    => ddr2_dq,        -- inout [15:0]
               ddr2_ext_local_init_done       => ddr2_init_done, -- out
               -- When USER auto-refresh controls ENABLED
--             ddr2_ext_local_refresh_chip => ddr2_refresh_chip, -- in
--             ddr2_ext_local_refresh_req  => ddr2_refresh_req,  -- in
               -- out
               ddr2_ext_local_refresh_ack     => OPEN,           -- out 
               ddr2_ext_reset_phy_clk_n       => OPEN,           -- out
               ddr2_ext_dll_reference_clk     => OPEN,           -- out
               ddr2_ext_dqs_delay_ctrl_export => OPEN,           -- out [5:0]
               ddr2_ext_local_autopch_req     => '0',            -- in
               ddr2_ext_local_self_rfsh_req   => '0',            -- in
               ddr2_ext_local_self_rfsh_chip  => '0',            -- in
               ddr2_ext_local_self_rfsh_ack   => OPEN );         -- out



  process (clk_50m_i)
  begin
    if (clk_50m_i'event and clk_50m_i = '1') then
      xrst0_q  <= xrst_i;
      xrst_q   <= xrst0_q;
    end if;
  end process;


  xrst_sys_w  <= xrst_q and ddr2_init_done;


  u_rv_soc : rv_soc
    port map ( clk_i           => clk_50m_i,
               xrst_i          => xrst_sys_w,
               -- AXI
               xmem_awready_i  => axi_awready_w,
               xmem_wready_i   => axi_wready_w,
               xmem_bvalid_i   => axi_bvalid_w,
               xmem_bresp_i    => axi_bresp_w,
               xmem_bid_i      => axi_bid_w,
               xmem_arready_i  => axi_arready_w,
               xmem_rvalid_i   => axi_rvalid_w,
               xmem_rdata_i    => axi_rdata_w,
               xmem_rresp_i    => axi_rresp_w,
               xmem_rid_i      => axi_rid_w,
               xmem_rlast_i    => axi_rlast_w,
               xmem_awvalid_o  => axi_awvalid_w,
               xmem_awaddr_o   => axi_awaddr_w,
               xmem_awid_o     => axi_awid_w,
               xmem_awlen_o    => axi_awlen_w,
               xmem_awburst_o  => axi_awburst_w,
               xmem_wvalid_o   => axi_wvalid_w,
               xmem_wdata_o    => axi_wdata_w,
               xmem_wstrb_o    => axi_wstrb_w,
               xmem_wlast_o    => axi_wlast_w,
               xmem_bready_o   => axi_bready_w,
               xmem_arvalid_o  => axi_arvalid_w,
               xmem_araddr_o   => axi_araddr_w,
               xmem_arid_o     => axi_arid_w,
               xmem_arlen_o    => axi_arlen_w,
               xmem_arburst_o  => axi_arburst_w,
               xmem_rready_o   => axi_rready_w,
               --  uarts
               uart_txd_i      => uart_txd_i,
               uart_rxd_o      => uart_rxd_o,
               uart2_txd_i     => uart2_txd_i,
               uart2_rxd_o     => uart2_rxd_o,
               --  spi
               spi_miso_i      => spi_miso_i,
               spi_clk_o       => spi_clk_o,
               spi_mosi_o      => spi_mosi_o,
               spi_cs_o        => spi_cs_o,
               --  gpio
               gpio_i          => gpio_i,
               gpio_oena_o     => gpio_oena_o,
               gpio_o          => gpio_o );


end rtl;
