-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--
-- 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_decode is
  generic ( RISCV_M             : sl_t := '1';    -- mul / div extension
            RISCV_A             : sl_t := '0';    -- amo extension
            RISCV_Zba           : sl_t := '0';    -- address generation (shXadd)
            RISCV_ZB            : sl_t := '0';    -- ZB extension
            EXTRA_DECODE_STAGE  : sl_t := '1' );
  port ( clk_i                   : in  std_logic;
         xrst_i                  : in  std_logic; -- syncr reset
         --  inputs
         fetch_in_valid_i        : in  std_logic;
         --  from fetch
         iword_i                 : in  slv_31_00;
         fetch_in_pc_i           : in  slv_31_00;
         fetch_in_fault_fetch_i  : in  std_logic;
         fetch_in_fault_page_i   : in  std_logic;
         fetch_out_accept_i      : in  std_logic;
         squash_decode_i         : in  std_logic;
         --  outputs
         fetch_out_valid_o       : out std_logic;
         iword_buf_o             : out slv_31_00;
         imem_pc_o               : out slv_31_00;
         fetch_out_fault_fetch_o : out std_logic;
         fetch_out_fault_page_o  : out std_logic;
         --
         alu_op_o                : out alu_op_t;
         lsu_op_p1_o             : out lsu_op_t;
         mul_op_p1_o             : out mul_op_t;
         div_op_p1_o             : out div_op_t;
         csr_op_o                : out csr_op_t;
         branch_op_o             : out branch_op_t;
         amo_op_o                : out amo_op_t;
         --
         pline_stall_i           : in  std_logic;
         pline_step_i            : in  std_logic;
         idec_group_o            : out i_group_t
         );
end entity rv_decode;


architecture rtl of rv_decode is

  component rv_decoder
    generic ( RISCV_M       : sl_t := '1';     -- mul / div extension
              RISCV_A       : sl_t := '0';     -- amo extension
              RISCV_Zba     : sl_t := '0';     -- address generation (shXadd)
              RISCV_ZB      : sl_t := '0' );   -- ZB extension
    port ( valid_i       : in sl_t;
           fetch_fault_i : in sl_t;
           iword_i       : in slv_31_00;
           --
           alu_op_o      : out alu_op_t;
           mul_op_o      : out mul_op_t;       -- mul,mulh, mulhsu, mulhu
           div_op_o      : out div_op_t;       -- div, divu, rem, remu
           lsu_op_o      : out lsu_op_t;
           csr_op_o      : out csr_op_t;
           branch_op_o   : out branch_op_t;
           amo_op_o      : out amo_op_t;
           --
           idec_group_o  : out i_group_t );
  end component;

  signal fetch_valid_p1q_p0_w     : sl_t;
  signal iword_p1q_p0_w           : slv_31_00;
  signal fetch_in_faults_p1q_p0_w : sl_t;

  signal fetch_fault_page_buf_q   : sl_t;
  signal fetch_fault_fetch_buf_q  : sl_t;
  signal fetch_pc_buf_q           : slv_t(fetch_in_pc_i'range);

  signal alu_op_p1_w              : alu_op_t;

begin

  u_dec : rv_decoder
    generic map ( RISCV_M       => RISCV_M,       -- mul / div extension
                  RISCV_A       => RISCV_A,       -- amo extension
                  RISCV_Zba     => RISCV_Zba,     -- address generation (shXadd)
                  RISCV_ZB      => RISCV_ZB )     -- ZB extension
    port map ( valid_i        => fetch_valid_p1q_p0_w,
               fetch_fault_i  => fetch_in_faults_p1q_p0_w,
               iword_i        => iword_p1q_p0_w,
               --
               alu_op_o       => alu_op_p1_w,        -- >>alu, p1
               mul_op_o       => mul_op_p1_o,        -- >>multiplier
               div_op_o       => div_op_p1_o,        -- >>divider
               lsu_op_o       => lsu_op_p1_o,
               csr_op_o       => csr_op_o,           -- >>csr
               branch_op_o    => branch_op_o,        -- >>exec
               amo_op_o       => amo_op_o,
               --
               idec_group_o   => idec_group_o );     -- >>iss, p1 (instr group)



  fetch_out_valid_o  <= fetch_valid_p1q_p0_w;
  iword_buf_o        <= iword_p1q_p0_w;


  -- (ALU has input registers so control signals must be delayed)
  p_alu_p2 : process (clk_i)
  begin
    if (clk_i'event and clk_i = '1') then
      if (xrst_i = '0') then
        alu_op_o    <= (alu_func4 => ALU_NONE,
                        zb_func5 => "00000", others => '0');
      else
        if (pline_stall_i = '1') then
          null;
        elsif (pline_step_i = '1') then
          alu_op_o  <= alu_op_p1_w;
        else
          alu_op_o  <= ( alu_func4 => ALU_NONE,
                         zb_func5 => "00000", others => '0' );
        end if;
      end if;
    end if;
  end process p_alu_p2;



  -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  --  extra decode stage (to improve cycle time)
  -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  g_extdec : if ( EXTRA_DECODE_STAGE /= '0') generate
    signal fetch_valid_p1_q    : sl_t;
    signal iword_p1_q          : slv_31_00;
  begin

    p_bufq : process (clk_i)
    begin
      if (clk_i'event and clk_i = '1') then
        if (xrst_i = '0') then
          fetch_valid_p1_q           <= '0';
          fetch_fault_page_buf_q     <= '0';
          fetch_fault_fetch_buf_q    <= '0';
          iword_p1_q                 <= X"00000000";
          fetch_pc_buf_q             <= X"00000000";
        else
          if (squash_decode_i = '1') then     -- branch / csr (irq | exception)
            fetch_valid_p1_q         <= '0';
            fetch_fault_page_buf_q   <= '0';
            fetch_fault_fetch_buf_q  <= '0';
            iword_p1_q               <= X"00000000";
            fetch_pc_buf_q           <= X"00000000";
          elsif (fetch_out_accept_i = '1' or fetch_valid_p1_q = '0') then
            fetch_valid_p1_q         <= fetch_in_valid_i;
            fetch_fault_page_buf_q   <= fetch_in_fault_page_i;
            fetch_fault_fetch_buf_q  <= fetch_in_fault_fetch_i;
            --
            if (fetch_in_fault_page_i = '0' and
                fetch_in_fault_fetch_i = '0') then
              iword_p1_q      <= iword_i;
            else
              iword_p1_q      <= X"00000000";
            end if;
            --
            fetch_pc_buf_q     <= fetch_in_pc_i;
          end if;
        end if;
      end if;
    end process p_bufq;

    fetch_valid_p1q_p0_w     <= fetch_valid_p1_q;
    fetch_in_faults_p1q_p0_w <= fetch_fault_page_buf_q or
                                fetch_fault_fetch_buf_q;
    iword_p1q_p0_w           <= iword_p1_q;

    fetch_out_fault_page_o   <= fetch_fault_page_buf_q;
    fetch_out_fault_fetch_o  <= fetch_fault_fetch_buf_q;
    imem_pc_o                <= fetch_pc_buf_q;

  end generate g_extdec;



  -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  --  straight through decode
  -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  g_noextdec : if ( EXTRA_DECODE_STAGE = '0' ) generate

  begin

    fetch_valid_p1q_p0_w     <= fetch_in_valid_i;
    fetch_in_faults_p1q_p0_w <= fetch_in_fault_fetch_i or fetch_in_fault_page_i;
    iword_p1q_p0_w           <= (others => '0')
                                when (fetch_in_fault_page_i = '1' or
                                      fetch_in_fault_fetch_i = '1')
                                else iword_i;

    -- outputs
    imem_pc_o               <= fetch_in_pc_i;
    fetch_out_fault_page_o  <= fetch_in_fault_page_i;
    fetch_out_fault_fetch_o <= fetch_in_fault_fetch_i;
  end generate g_noextdec;

end rtl;
