Line 58... |
Line 58... |
);
|
);
|
end neorv32_cpu_cp_muldiv;
|
end neorv32_cpu_cp_muldiv;
|
|
|
architecture neorv32_cpu_cp_muldiv_rtl of neorv32_cpu_cp_muldiv is
|
architecture neorv32_cpu_cp_muldiv_rtl of neorv32_cpu_cp_muldiv is
|
|
|
-- constants --
|
-- configuration - still experimental --
|
constant all_zero_c : std_ulogic_vector(data_width_c-1 downto 0) := (others => '0');
|
constant FAST_MUL_EN : boolean := false; -- use DSPs for faster multiplication
|
|
|
-- controller --
|
-- controller --
|
type state_t is (IDLE, DECODE, INIT_OPX, INIT_OPY, PROCESSING, FINALIZE, COMPLETED);
|
type state_t is (IDLE, DECODE, INIT_OPX, INIT_OPY, PROCESSING, FINALIZE, COMPLETED);
|
signal state : state_t;
|
signal state : state_t;
|
signal cnt : std_ulogic_vector(4 downto 0);
|
signal cnt : std_ulogic_vector(4 downto 0);
|
Line 84... |
Line 84... |
signal div_sign_comp : std_ulogic_vector(data_width_c-1 downto 0);
|
signal div_sign_comp : std_ulogic_vector(data_width_c-1 downto 0);
|
signal div_res : std_ulogic_vector(data_width_c-1 downto 0);
|
signal div_res : std_ulogic_vector(data_width_c-1 downto 0);
|
|
|
-- multiplier core --
|
-- multiplier core --
|
signal mul_product : std_ulogic_vector(63 downto 0);
|
signal mul_product : std_ulogic_vector(63 downto 0);
|
signal mul_do_add : std_ulogic_vector(32 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 : std_ulogic_vector(32 downto 0);
|
|
signal mul_op_y : std_ulogic_vector(32 downto 0);
|
|
signal mul_buf_ff0 : std_ulogic_vector(65 downto 0);
|
|
signal mul_buf_ff1 : std_ulogic_vector(65 downto 0);
|
|
|
begin
|
begin
|
|
|
-- Co-Processor Controller ----------------------------------------------------------------
|
-- Co-Processor Controller ----------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
Line 120... |
Line 124... |
if (ctrl_i(ctrl_cp_use_c) = '1') and (ctrl_i(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) = cp_sel_muldiv_c) then
|
if (ctrl_i(ctrl_cp_use_c) = '1') and (ctrl_i(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) = cp_sel_muldiv_c) then
|
state <= DECODE;
|
state <= DECODE;
|
end if;
|
end if;
|
|
|
when DECODE =>
|
when DECODE =>
|
cnt <= "11111";
|
--
|
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 <= opx(opx'left) xor opy(opy'left);
|
div_res_corr <= opx(opx'left) xor opy(opy'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 <= opx(opx'left);
|
div_res_corr <= opx(opx'left);
|
else
|
else
|
div_res_corr <= '0';
|
div_res_corr <= '0';
|
end if;
|
end if;
|
-- if (cp_op = cp_op_div_c) and (opy = all_zero_c) then -- *divide* by 0?
|
--
|
if (opy = all_zero_c) then -- *divide* by 0?
|
if (or_all_f(opy) = '0') then -- *divide* by 0?
|
opy_is_zero <= '1';
|
opy_is_zero <= '1';
|
else
|
else
|
opy_is_zero <= '0';
|
opy_is_zero <= '0';
|
end if;
|
end if;
|
|
--
|
if (operation = '1') then -- division
|
if (operation = '1') then -- division
|
|
cnt <= "11111";
|
state <= INIT_OPX;
|
state <= INIT_OPX;
|
else -- multiplication
|
else -- multiplication
|
|
if (FAST_MUL_EN = false) then
|
|
cnt <= "11111";
|
|
else
|
|
cnt <= "00101"; -- FIXME
|
|
end if;
|
start <= '1';
|
start <= '1';
|
state <= PROCESSING;
|
state <= PROCESSING;
|
end if;
|
end if;
|
|
|
when INIT_OPX =>
|
when INIT_OPX =>
|
Line 180... |
Line 191... |
|
|
-- opy (rs2) signed? --
|
-- opy (rs2) signed? --
|
opy_is_signed <= '1' when (cp_op = cp_op_mulh_c) or (cp_op = cp_op_div_c) or (cp_op = cp_op_rem_c) else '0';
|
opy_is_signed <= '1' when (cp_op = cp_op_mulh_c) or (cp_op = cp_op_div_c) or (cp_op = cp_op_rem_c) else '0';
|
|
|
|
|
-- Multiplier Core ------------------------------------------------------------------------
|
-- Multiplier Core (signed) ---------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
multiplier_core: process(clk_i)
|
multiplier_core: process(clk_i)
|
begin
|
begin
|
if rising_edge(clk_i) then
|
if rising_edge(clk_i) then
|
|
if (FAST_MUL_EN = false) then -- use small iterative computation
|
if (start = '1') then -- start new multiplication
|
if (start = '1') then -- start new multiplication
|
mul_product(63 downto 32) <= (others => '0');
|
mul_product(63 downto 32) <= (others => '0');
|
mul_product(31 downto 00) <= opy;
|
mul_product(31 downto 00) <= opy;
|
elsif ((state = PROCESSING) or (state = FINALIZE)) and (operation = '0') then
|
elsif ((state = PROCESSING) or (state = FINALIZE)) and (operation = '0') then
|
mul_product(63 downto 31) <= mul_do_add(32 downto 0);
|
mul_product(63 downto 31) <= mul_do_add(32 downto 0);
|
mul_product(30 downto 00) <= mul_product(31 downto 1);
|
mul_product(30 downto 00) <= mul_product(31 downto 1);
|
end if;
|
end if;
|
|
else -- use direct approach using (several!) DSP blocks
|
|
if (start = '1') then
|
|
mul_op_x <= (opx(opx'left) and opx_is_signed) & opx;
|
|
mul_op_y <= (opy(opy'left) and opy_is_signed) & opy;
|
|
end if;
|
|
mul_buf_ff0 <= std_ulogic_vector(signed(mul_op_x) * signed(mul_op_y));
|
|
mul_buf_ff1 <= mul_buf_ff0;
|
|
mul_product <= mul_buf_ff1(63 downto 0); -- let the register balancing do the magic here
|
|
end if;
|
end if;
|
end if;
|
end process multiplier_core;
|
end process multiplier_core;
|
|
|
-- MUL: do another addition --
|
-- MUL: do another addition --
|
mul_update: process(mul_product, mul_sign_cycle, mul_p_sext, opx_is_signed, opx)
|
mul_update: process(mul_product, mul_sign_cycle, mul_p_sext, opx_is_signed, opx)
|
begin
|
begin
|
if (mul_product(0) = '1') then
|
-- current bit of opy to take care of --
|
if (mul_sign_cycle = '1') then -- for signed operation only: take care of negative weighted MSB
|
if (mul_product(0) = '1') then -- multiply with 1
|
|
if (mul_sign_cycle = '1') then -- for signed operations only: take care of negative weighted MSB -> multiply with -1
|
mul_do_add <= std_ulogic_vector(unsigned(mul_p_sext & mul_product(63 downto 32)) - unsigned((opx(opx'left) and opx_is_signed) & opx));
|
mul_do_add <= std_ulogic_vector(unsigned(mul_p_sext & mul_product(63 downto 32)) - unsigned((opx(opx'left) and opx_is_signed) & opx));
|
else
|
else -- multiply with +1
|
mul_do_add <= std_ulogic_vector(unsigned(mul_p_sext & mul_product(63 downto 32)) + unsigned((opx(opx'left) and opx_is_signed) & opx));
|
mul_do_add <= std_ulogic_vector(unsigned(mul_p_sext & mul_product(63 downto 32)) + unsigned((opx(opx'left) and opx_is_signed) & opx));
|
end if;
|
end if;
|
else
|
else -- multiply with 0
|
mul_do_add <= mul_p_sext & mul_product(63 downto 32);
|
mul_do_add <= mul_p_sext & mul_product(63 downto 32);
|
end if;
|
end if;
|
end process mul_update;
|
end process mul_update;
|
|
|
-- sign control --
|
-- sign control --
|
mul_sign_cycle <= opy_is_signed when (state = FINALIZE) else '0';
|
mul_sign_cycle <= opy_is_signed when (state = FINALIZE) else '0';
|
mul_p_sext <= mul_product(mul_product'left) and opx_is_signed;
|
mul_p_sext <= mul_product(mul_product'left) and opx_is_signed;
|
|
|
|
|
-- Divider Core ---------------------------------------------------------------------------
|
-- Divider Core (unsigned) ----------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
divider_core: process(clk_i)
|
divider_core: process(clk_i)
|
begin
|
begin
|
if rising_edge(clk_i) then
|
if rising_edge(clk_i) then
|
if (start = '1') then -- start new division
|
if (start = '1') then -- start new division
|