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

Subversion Repositories neorv32

[/] [neorv32/] [trunk/] [rtl/] [core/] [neorv32_cpu_cp_muldiv.vhd] - Diff between revs 62 and 69

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

Rev 62 Rev 69
Line 77... Line 77...
  constant cp_op_divu_c   : std_ulogic_vector(2 downto 0) := "101"; -- divu
  constant cp_op_divu_c   : std_ulogic_vector(2 downto 0) := "101"; -- divu
  constant cp_op_rem_c    : std_ulogic_vector(2 downto 0) := "110"; -- rem
  constant cp_op_rem_c    : std_ulogic_vector(2 downto 0) := "110"; -- rem
  constant cp_op_remu_c   : std_ulogic_vector(2 downto 0) := "111"; -- remu
  constant cp_op_remu_c   : std_ulogic_vector(2 downto 0) := "111"; -- remu
 
 
  -- controller --
  -- controller --
  type state_t is (IDLE, DIV_PREPROCESS, PROCESSING, FINALIZE, COMPLETED);
  type state_t is (IDLE, DIV_PREPROCESS, PROCESSING, FINALIZE);
  signal state         : state_t;
  signal state         : state_t;
  signal cnt           : std_ulogic_vector(4 downto 0);
  signal cnt           : std_ulogic_vector(4 downto 0);
  signal cp_op         : std_ulogic_vector(2 downto 0); -- operation to execute
  signal cp_op         : std_ulogic_vector(2 downto 0); -- operation to execute
  signal cp_op_ff      : std_ulogic_vector(2 downto 0); -- operation that was executed
  signal cp_op_ff      : std_ulogic_vector(2 downto 0); -- operation that was executed
  signal start_div     : std_ulogic;
  signal start_div     : std_ulogic;
  signal start_mul     : std_ulogic;
  signal start_mul     : std_ulogic;
  signal operation     : std_ulogic;
  signal operation     : std_ulogic;
  signal div_opx       : std_ulogic_vector(data_width_c-1 downto 0);
 
  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 opy_is_zero   : std_ulogic;
  signal div_res_corr  : std_ulogic;
  signal div_res_corr  : std_ulogic;
  signal valid         : 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);
  signal quotient         : std_ulogic_vector(data_width_c-1 downto 0);
  signal quotient         : std_ulogic_vector(data_width_c-1 downto 0);
  signal div_sub          : std_ulogic_vector(data_width_c   downto 0);
  signal div_sub          : std_ulogic_vector(data_width_c   downto 0);
Line 108... Line 107...
  signal mul_do_add     : std_ulogic_vector(data_width_c downto 0);
  signal mul_do_add     : std_ulogic_vector(data_width_c downto 0);
  signal mul_sign_cycle : std_ulogic;
  signal mul_sign_cycle : std_ulogic;
  signal mul_p_sext     : std_ulogic;
  signal mul_p_sext     : std_ulogic;
  signal mul_op_x       : signed(32 downto 0); -- for using DSPs
  signal mul_op_x       : signed(32 downto 0); -- for using DSPs
  signal mul_op_y       : signed(32 downto 0); -- for using DSPs
  signal mul_op_y       : signed(32 downto 0); -- for using DSPs
  signal mul_buf_ff     : signed(65 downto 0); -- for using DSPs
 
 
 
begin
begin
 
 
  -- Co-Processor Controller ----------------------------------------------------------------
  -- Co-Processor Controller ----------------------------------------------------------------
  -- -------------------------------------------------------------------------------------------
  -- -------------------------------------------------------------------------------------------
  coprocessor_ctrl: process(rstn_i, clk_i)
  coprocessor_ctrl: process(rstn_i, clk_i)
  begin
  begin
    if (rstn_i = '0') then
    if (rstn_i = '0') then
      state        <= IDLE;
      state        <= IDLE;
      div_opx      <= (others => def_rst_val_c);
 
      div_opy      <= (others => def_rst_val_c);
      div_opy      <= (others => def_rst_val_c);
      cnt          <= (others => def_rst_val_c);
      cnt          <= (others => def_rst_val_c);
      cp_op_ff     <= (others => def_rst_val_c);
      cp_op_ff     <= (others => def_rst_val_c);
      start_div    <= '0';
      start_div    <= '0';
      valid        <= '0';
      out_en       <= '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;
      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';
      valid     <= '0';
      out_en    <= '0';
 
      valid_o   <= '0';
 
 
      -- FSM --
      -- FSM --
      case state is
      case state is
 
 
        when IDLE =>
        when IDLE =>
          cp_op_ff <= cp_op;
          cp_op_ff <= cp_op;
 
          cnt      <= "11110";
          if (start_i = '1') then
          if (start_i = '1') then
            if (operation = '1') and (DIVISION_EN = true) then -- division
            if (operation = '1') and (DIVISION_EN = true) then -- division
              cnt <= "11111";
              start_div <= '1';
              state <= DIV_PREPROCESS;
              state <= DIV_PREPROCESS;
            else
            else -- multiplication
              cnt <= "11110";
 
              if (FAST_MUL_EN = true) then
              if (FAST_MUL_EN = true) then
 
                valid_o <= '1';
                state <= FINALIZE;
                state <= FINALIZE;
              else
              else
                state <= PROCESSING;
                state <= PROCESSING;
              end if;
              end if;
            end if;
            end if;
          end if;
          end if;
 
 
        when DIV_PREPROCESS =>
        when DIV_PREPROCESS =>
          if (DIVISION_EN = true) then
          -- check relevant input signs --
            -- check rlevatn input signs --
 
            if (cp_op = cp_op_div_c) then -- result sign compensation for div?
            if (cp_op = cp_op_div_c) then -- result sign compensation for div?
              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);
            elsif (cp_op = cp_op_rem_c) then -- result sign compensation for rem?
            elsif (cp_op = cp_op_rem_c) then -- result sign compensation for rem?
              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? --
            -- divide by zero? --
            opy_is_zero <= not or_reduce_f(rs2_i); -- set if rs2 = 0
            opy_is_zero <= not or_reduce_f(rs2_i); -- set if rs2 = 0
            -- abs(rs1) --
 
            if ((rs1_i(rs1_i'left) and rs1_is_signed) = '1') then -- signed division?
 
              div_opx <= std_ulogic_vector(0 - unsigned(rs1_i)); -- make positive
 
            else
 
              div_opx <= rs1_i;
 
            end if;
 
            -- 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;
            --
            --
            start_div <= '1';
 
            state     <= PROCESSING;
            state     <= PROCESSING;
          else
 
            state <= IDLE;
 
          end if;
 
 
 
        when PROCESSING =>
        when PROCESSING =>
          cnt <= std_ulogic_vector(unsigned(cnt) - 1);
          cnt <= std_ulogic_vector(unsigned(cnt) - 1);
          if (cnt = "00000") then
          if (cnt = "00000") then
 
            valid_o <= '1';
            state <= FINALIZE;
            state <= FINALIZE;
          end if;
          end if;
 
 
        when FINALIZE =>
        when FINALIZE =>
          state <= COMPLETED;
          out_en <= '1';
 
          state  <= IDLE;
 
 
        when COMPLETED =>
        when others =>
          valid <= '1';
 
          state <= IDLE;
          state <= IDLE;
      end case;
      end case;
    end if;
    end if;
  end process coprocessor_ctrl;
  end process coprocessor_ctrl;
 
 
Line 233... Line 224...
        end if;
        end if;
      end if;
      end if;
    end process multiplier_core;
    end process multiplier_core;
  end generate;
  end generate;
 
 
  -- parallel multiplication --
  -- parallel multiplication (using DSP blocks) --
  multiplier_core_dsp:
  multiplier_core_dsp:
  if (FAST_MUL_EN = true) generate
  if (FAST_MUL_EN = true) generate
    multiplier_core: process(clk_i)
    multiplier_core: process(clk_i)
 
      variable tmp_v : signed(65 downto 0);
    begin
    begin
      if rising_edge(clk_i) then
      if rising_edge(clk_i) then
        if (start_mul = '1') then
        if (start_mul = '1') then
          mul_op_x <= signed((rs1_i(rs1_i'left) and rs1_is_signed) & rs1_i);
          mul_op_x <= signed((rs1_i(rs1_i'left) and rs1_is_signed) & rs1_i);
          mul_op_y <= signed((rs2_i(rs2_i'left) and rs2_is_signed) & rs2_i);
          mul_op_y <= signed((rs2_i(rs2_i'left) and rs2_is_signed) & rs2_i);
        end if;
        end if;
        mul_buf_ff  <= mul_op_x * mul_op_y;
        tmp_v := mul_op_x * mul_op_y;
        mul_product <= std_ulogic_vector(mul_buf_ff(63 downto 0)); -- let the register balancing do the magic here
        mul_product <= std_ulogic_vector(tmp_v(63 downto 0));
 
        --mul_buf_ff  <= mul_op_x * mul_op_y;
 
        --mul_product <= std_ulogic_vector(mul_buf_ff(63 downto 0)); -- let the register balancing do the magic here
      end if;
      end if;
    end process multiplier_core;
    end process multiplier_core;
  end generate;
  end generate;
 
 
  -- do another addition (bit-serial) --
  -- do another addition (bit-serial) --
Line 280... Line 274...
      if (rstn_i = '0') then
      if (rstn_i = '0') then
        quotient  <= (others => def_rst_val_c);
        quotient  <= (others => def_rst_val_c);
        remainder <= (others => def_rst_val_c);
        remainder <= (others => def_rst_val_c);
      elsif rising_edge(clk_i) then
      elsif rising_edge(clk_i) then
        if (start_div = '1') then -- start new division
        if (start_div = '1') then -- start new division
          quotient  <= div_opx;
          if ((rs1_i(rs1_i'left) and rs1_is_signed) = '1') then -- signed division?
 
            quotient <= std_ulogic_vector(0 - unsigned(rs1_i)); -- make positive
 
          else
 
            quotient <= rs1_i;
 
          end if;
          remainder <= (others => '0');
          remainder <= (others => '0');
        elsif (state = PROCESSING) or (state = FINALIZE) then -- running?
        elsif (state = PROCESSING) or (state = FINALIZE) then -- running?
          quotient <= quotient(30 downto 0) & (not div_sub(32));
          quotient <= quotient(30 downto 0) & (not div_sub(32));
          if (div_sub(32) = '0') then -- still overflowing
          if (div_sub(32) = '0') then -- still overflowing
            remainder <= div_sub(31 downto 0);
            remainder <= div_sub(31 downto 0);
Line 305... Line 303...
  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 => '-');
    remainder <= (others => '0');
    quotient  <= (others => '-');
    quotient  <= (others => '0');
    div_res   <= (others => '-');
    div_res   <= (others => '0');
  end generate;
  end generate;
 
 
 
 
  -- Data Output ----------------------------------------------------------------------------
  -- Data Output ----------------------------------------------------------------------------
  -- -------------------------------------------------------------------------------------------
  -- -------------------------------------------------------------------------------------------
  operation_result: process(rstn_i, clk_i)
  operation_result: process(out_en, cp_op_ff, mul_product, div_res, quotient, opy_is_zero, rs1_i, remainder)
  begin
  begin
    if (rstn_i = '0') then
    if (out_en = '1') then
      res_o <= (others => def_rst_val_c);
 
    elsif rising_edge(clk_i) then
 
      res_o <= (others => '0');
 
      if (valid = '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 =>
            if (DIVISION_EN = true) then res_o <= div_res; else NULL; end if;
          res_o <= div_res;
          when cp_op_divu_c =>
          when cp_op_divu_c =>
            if (DIVISION_EN = true) then res_o <= quotient; else NULL; end if;
          res_o <= quotient;
          when cp_op_rem_c =>
          when cp_op_rem_c =>
            if (DIVISION_EN = true) then
 
              if (opy_is_zero = '0') then
              if (opy_is_zero = '0') then
                res_o <= div_res;
                res_o <= div_res;
              else
              else
                res_o <= rs1_i;
                res_o <= rs1_i;
              end if;
              end if;
            else
 
              NULL;
 
            end if;
 
          when others => -- cp_op_remu_c
          when others => -- cp_op_remu_c
            if (DIVISION_EN = true) then res_o <= remainder; else NULL; end if;
          res_o <= remainder;
        end case;
        end case;
      end if;
    else
 
      res_o <= (others => '0');
    end if;
    end if;
  end process operation_result;
  end process operation_result;
 
 
  -- status output --
 
  valid_o <= valid;
 
 
 
 
 
end neorv32_cpu_cp_muldiv_rtl;
end neorv32_cpu_cp_muldiv_rtl;
 
 
 No newline at end of file
 No newline at end of file

powered by: WebSVN 2.1.0

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