OpenCores
URL https://opencores.org/ocsvn/neorv32/neorv32/trunk

Subversion Repositories neorv32

[/] [neorv32/] [trunk/] [rtl/] [core/] [neorv32_cpu_cp_muldiv.vhd] - Diff between revs 71 and 73

Go to most recent revision | Show entire file | Details | Blame | View Log

Rev 71 Rev 73
Line 1... Line 1...
-- #################################################################################################
-- #################################################################################################
-- # << NEORV32 - CPU Co-Processor: Integer Multiplier/Divider Unit (RISC-V "M" Extension) >>      #
-- # << NEORV32 - CPU Co-Processor: Integer Multiplier/Divider Unit (RISC-V "M" Extension) >>      #
-- # ********************************************************************************************* #
-- # ********************************************************************************************* #
-- # Multiplier and Divider unit. Implements the RISC-V M CPU extension.                           #
-- # Multiplier and Divider unit. Implements the RISC-V M & Zmmul CPU extensions.                  #
-- #                                                                                               #
 
-- # Multiplier core (signed/unsigned) uses classical serial algorithm. Unit latency: 31+3 cycles  #
 
-- # Divider core (unsigned) uses classical serial algorithm. Unit latency: 32+4 cycles            #
 
-- #                                                                                               #
-- #                                                                                               #
 
-- # Multiplier core (signed/unsigned) uses classical serial algorithm. Latency = 31+3 cycles.     #
-- # Multiplications can be mapped to DSP blocks (faster!) when FAST_MUL_EN = true.                #
-- # Multiplications can be mapped to DSP blocks (faster!) when FAST_MUL_EN = true.                #
 
-- # Divider core (unsigned-only) uses classical serial algorithm. latency = 32+4 cycles.          #
-- # ********************************************************************************************* #
-- # ********************************************************************************************* #
-- # BSD 3-Clause License                                                                          #
-- # BSD 3-Clause License                                                                          #
-- #                                                                                               #
-- #                                                                                               #
-- # Copyright (c) 2022, Stephan Nolting. All rights reserved.                                     #
-- # Copyright (c) 2022, Stephan Nolting. All rights reserved.                                     #
-- #                                                                                               #
-- #                                                                                               #
Line 88... Line 87...
  signal start_mul     : std_ulogic;
  signal start_mul     : std_ulogic;
  signal operation     : std_ulogic;
  signal operation     : std_ulogic;
  signal div_opy       : std_ulogic_vector(data_width_c-1 downto 0);
  signal div_opy       : std_ulogic_vector(data_width_c-1 downto 0);
  signal rs1_is_signed : std_ulogic;
  signal rs1_is_signed : std_ulogic;
  signal rs2_is_signed : std_ulogic;
  signal rs2_is_signed : std_ulogic;
  signal opy_is_zero   : std_ulogic;
 
  signal div_res_corr  : std_ulogic;
  signal div_res_corr  : std_ulogic;
  signal out_en        : std_ulogic;
  signal out_en        : std_ulogic;
 
 
  -- divider core --
  -- divider core --
  signal remainder        : std_ulogic_vector(data_width_c-1 downto 0);
  signal remainder        : std_ulogic_vector(data_width_c-1 downto 0);
Line 123... Line 121...
      cp_op_ff     <= (others => def_rst_val_c);
      cp_op_ff     <= (others => def_rst_val_c);
      start_div    <= '0';
      start_div    <= '0';
      out_en       <= '0';
      out_en       <= '0';
      valid_o      <= '0';
      valid_o      <= '0';
      div_res_corr <= def_rst_val_c;
      div_res_corr <= def_rst_val_c;
      opy_is_zero  <= def_rst_val_c;
 
    elsif rising_edge(clk_i) then
    elsif rising_edge(clk_i) then
      -- defaults --
      -- defaults --
      start_div <= '0';
      start_div <= '0';
      out_en    <= '0';
      out_en    <= '0';
      valid_o   <= '0';
      valid_o   <= '0';
Line 151... Line 148...
              end if;
              end if;
            end if;
            end if;
          end if;
          end if;
 
 
        when DIV_PREPROCESS =>
        when DIV_PREPROCESS =>
          -- check relevant input signs --
          -- check relevant input signs for result sign compensation --
          if (cp_op = cp_op_div_c) then -- result sign compensation for div?
          if (cp_op = cp_op_div_c) then -- signed div operation
            div_res_corr <= rs1_i(rs1_i'left) xor rs2_i(rs2_i'left);
            div_res_corr <= (rs1_i(rs1_i'left) xor rs2_i(rs2_i'left)) and or_reduce_f(rs2_i); -- different signs AND rs2 not zero
          elsif (cp_op = cp_op_rem_c) then -- result sign compensation for rem?
          elsif (cp_op = cp_op_rem_c) then -- signed rem operation
            div_res_corr <= rs1_i(rs1_i'left);
            div_res_corr <= rs1_i(rs1_i'left);
          else
          else
            div_res_corr <= '0';
            div_res_corr <= '0';
          end if;
          end if;
          -- divide by zero? --
 
          opy_is_zero <= not or_reduce_f(rs2_i); -- set if rs2 = 0
 
          -- abs(rs2) --
          -- abs(rs2) --
          if ((rs2_i(rs2_i'left) and rs2_is_signed) = '1') then -- signed division?
          if ((rs2_i(rs2_i'left) and rs2_is_signed) = '1') then -- signed division?
            div_opy <= std_ulogic_vector(0 - unsigned(rs2_i)); -- make positive
            div_opy <= std_ulogic_vector(0 - unsigned(rs2_i)); -- make positive
          else
          else
            div_opy <= rs2_i;
            div_opy <= rs2_i;
          end if;
          end if;
          --
 
          state <= PROCESSING;
          state <= PROCESSING;
 
 
        when PROCESSING =>
        when PROCESSING =>
          cnt <= std_ulogic_vector(unsigned(cnt) - 1);
          cnt <= std_ulogic_vector(unsigned(cnt) - 1);
          if (cnt = "00000") or (ctrl_i(ctrl_trap_c) = '1') then -- abort on trap
          if (cnt = "00000") or (ctrl_i(ctrl_trap_c) = '1') then -- abort on trap
Line 295... Line 289...
 
 
    -- try another subtraction --
    -- try another subtraction --
    div_sub <= std_ulogic_vector(unsigned('0' & remainder(30 downto 0) & quotient(31)) - unsigned('0' & div_opy));
    div_sub <= std_ulogic_vector(unsigned('0' & remainder(30 downto 0) & quotient(31)) - unsigned('0' & div_opy));
 
 
    -- result sign compensation --
    -- result sign compensation --
    div_sign_comp_in <= quotient when (cp_op = cp_op_div_c) else remainder;
    div_sign_comp_in <= quotient when (cp_op = cp_op_div_c) or (cp_op = cp_op_divu_c) else remainder;
    div_sign_comp    <= std_ulogic_vector(0 - unsigned(div_sign_comp_in));
    div_sign_comp    <= std_ulogic_vector(0 - unsigned(div_sign_comp_in));
    div_res          <= div_sign_comp when (div_res_corr = '1') and (opy_is_zero = '0') else div_sign_comp_in;
    div_res          <= div_sign_comp when (div_res_corr = '1') else div_sign_comp_in;
  end generate;
  end generate;
 
 
  -- no divider --
  -- no divider --
  divider_core_serial_none:
  divider_core_serial_none:
  if (DIVISION_EN = false) generate
  if (DIVISION_EN = false) generate
    remainder <= (others => '0');
    remainder <= (others => '0');
    quotient  <= (others => '0');
    quotient  <= (others => '0');
 
    div_sub          <= (others => '0');
 
    div_sign_comp_in <= (others => '0');
 
    div_sign_comp    <= (others => '0');
    div_res   <= (others => '0');
    div_res   <= (others => '0');
  end generate;
  end generate;
 
 
 
 
  -- Data Output ----------------------------------------------------------------------------
  -- Data Output ----------------------------------------------------------------------------
  -- -------------------------------------------------------------------------------------------
  -- -------------------------------------------------------------------------------------------
  operation_result: process(out_en, cp_op_ff, mul_product, div_res, quotient, opy_is_zero, rs1_i, remainder)
  operation_result: process(out_en, cp_op_ff, mul_product, div_res, div_sign_comp_in)
  begin
  begin
    if (out_en = '1') then
    if (out_en = '1') then
      case cp_op_ff is
      case cp_op_ff is
        when cp_op_mul_c =>
        when cp_op_mul_c =>
          res_o <= mul_product(31 downto 00);
          res_o <= mul_product(31 downto 00);
        when cp_op_mulh_c | cp_op_mulhsu_c | cp_op_mulhu_c =>
        when cp_op_mulh_c | cp_op_mulhsu_c | cp_op_mulhu_c =>
          res_o <= mul_product(63 downto 32);
          res_o <= mul_product(63 downto 32);
        when cp_op_div_c =>
        when cp_op_div_c | cp_op_rem_c =>
          res_o <= div_res;
 
        when cp_op_divu_c =>
 
          res_o <= quotient;
 
        when cp_op_rem_c =>
 
          if (opy_is_zero = '0') then
 
            res_o <= div_res;
            res_o <= div_res;
          else
        when others => -- cp_op_divu_c | cp_op_remu_c
            res_o <= rs1_i;
          res_o <= div_sign_comp_in;
          end if;
 
        when others => -- cp_op_remu_c
 
          res_o <= remainder;
 
      end case;
      end case;
    else
    else
      res_o <= (others => '0');
      res_o <= (others => '0');
    end if;
    end if;
  end process operation_result;
  end process operation_result;

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.