Line 1... |
Line 1... |
-- #################################################################################################
|
-- #################################################################################################
|
-- # << NEORV32 - Arithmetical/Logical Unit >> #
|
-- # << NEORV32 - Arithmetical/Logical Unit >> #
|
-- # ********************************************************************************************* #
|
-- # ********************************************************************************************* #
|
-- # Main data and address ALU. Includes comparator unit and co-processor interface/arbiter. #
|
-- # Main data and address ALU and co-processor interface/arbiter. #
|
-- # ********************************************************************************************* #
|
-- # ********************************************************************************************* #
|
-- # BSD 3-Clause License #
|
-- # BSD 3-Clause License #
|
-- # #
|
-- # #
|
-- # Copyright (c) 2021, Stephan Nolting. All rights reserved. #
|
-- # Copyright (c) 2021, Stephan Nolting. All rights reserved. #
|
-- # #
|
-- # #
|
Line 55... |
Line 55... |
rs1_i : in std_ulogic_vector(data_width_c-1 downto 0); -- rf source 1
|
rs1_i : in std_ulogic_vector(data_width_c-1 downto 0); -- rf source 1
|
rs2_i : in std_ulogic_vector(data_width_c-1 downto 0); -- rf source 2
|
rs2_i : in std_ulogic_vector(data_width_c-1 downto 0); -- rf source 2
|
pc2_i : in std_ulogic_vector(data_width_c-1 downto 0); -- delayed PC
|
pc2_i : in std_ulogic_vector(data_width_c-1 downto 0); -- delayed PC
|
imm_i : in std_ulogic_vector(data_width_c-1 downto 0); -- immediate
|
imm_i : in std_ulogic_vector(data_width_c-1 downto 0); -- immediate
|
-- data output --
|
-- data output --
|
cmp_o : out std_ulogic_vector(1 downto 0); -- comparator status
|
|
res_o : out std_ulogic_vector(data_width_c-1 downto 0); -- ALU result
|
res_o : out std_ulogic_vector(data_width_c-1 downto 0); -- ALU result
|
add_o : out std_ulogic_vector(data_width_c-1 downto 0); -- address computation result
|
add_o : out std_ulogic_vector(data_width_c-1 downto 0); -- address computation result
|
-- co-processor interface --
|
-- co-processor interface --
|
cp0_start_o : out std_ulogic; -- trigger co-processor 0
|
cp0_start_o : out std_ulogic; -- trigger co-processor 0
|
cp0_data_i : in std_ulogic_vector(data_width_c-1 downto 0); -- co-processor 0 result
|
cp0_data_i : in std_ulogic_vector(data_width_c-1 downto 0); -- co-processor 0 result
|
Line 88... |
Line 87... |
--
|
--
|
signal cp_res : std_ulogic_vector(data_width_c-1 downto 0);
|
signal cp_res : std_ulogic_vector(data_width_c-1 downto 0);
|
signal arith_res : std_ulogic_vector(data_width_c-1 downto 0);
|
signal arith_res : std_ulogic_vector(data_width_c-1 downto 0);
|
signal logic_res : std_ulogic_vector(data_width_c-1 downto 0);
|
signal logic_res : std_ulogic_vector(data_width_c-1 downto 0);
|
|
|
-- comparator --
|
|
signal cmp_opx : std_ulogic_vector(data_width_c downto 0);
|
|
signal cmp_opy : std_ulogic_vector(data_width_c downto 0);
|
|
signal cmp_sub : std_ulogic_vector(data_width_c downto 0);
|
|
|
|
-- shifter --
|
-- shifter --
|
type shifter_t is record
|
type shifter_t is record
|
cmd : std_ulogic;
|
cmd : std_ulogic;
|
cmd_ff : std_ulogic;
|
cmd_ff : std_ulogic;
|
start : std_ulogic;
|
start : std_ulogic;
|
Line 126... |
Line 120... |
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
opa <= pc2_i when (ctrl_i(ctrl_alu_opa_mux_c) = '1') else rs1_i; -- operand a (first ALU input operand), only required for arithmetic ops
|
opa <= pc2_i when (ctrl_i(ctrl_alu_opa_mux_c) = '1') else rs1_i; -- operand a (first ALU input operand), only required for arithmetic ops
|
opb <= imm_i when (ctrl_i(ctrl_alu_opb_mux_c) = '1') else rs2_i; -- operand b (second ALU input operand)
|
opb <= imm_i when (ctrl_i(ctrl_alu_opb_mux_c) = '1') else rs2_i; -- operand b (second ALU input operand)
|
|
|
|
|
-- Comparator Unit ------------------------------------------------------------------------
|
|
-- -------------------------------------------------------------------------------------------
|
|
cmp_opx <= (rs1_i(rs1_i'left) and (not ctrl_i(ctrl_alu_unsigned_c))) & rs1_i;
|
|
cmp_opy <= (rs2_i(rs2_i'left) and (not ctrl_i(ctrl_alu_unsigned_c))) & rs2_i;
|
|
cmp_sub <= std_ulogic_vector(signed(cmp_opx) - signed(cmp_opy)); -- less than (x < y)
|
|
|
|
cmp_o(alu_cmp_equal_c) <= '1' when (rs1_i = rs2_i) else '0';
|
|
cmp_o(alu_cmp_less_c) <= cmp_sub(cmp_sub'left); -- less = carry (borrow)
|
|
|
|
|
|
-- Binary Adder/Subtractor ----------------------------------------------------------------
|
-- Binary Adder/Subtractor ----------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
binary_arithmetic_core: process(ctrl_i, opa, opb)
|
binary_arithmetic_core: process(ctrl_i, opa, opb)
|
variable cin_v : std_ulogic_vector(0 downto 0);
|
variable cin_v : std_ulogic_vector(0 downto 0);
|
variable op_a_v : std_ulogic_vector(data_width_c downto 0);
|
variable op_a_v : std_ulogic_vector(data_width_c downto 0);
|
Line 148... |
Line 132... |
variable res_v : std_ulogic_vector(data_width_c downto 0);
|
variable res_v : std_ulogic_vector(data_width_c downto 0);
|
begin
|
begin
|
-- operand sign-extension --
|
-- operand sign-extension --
|
op_a_v := (opa(opa'left) and (not ctrl_i(ctrl_alu_unsigned_c))) & opa;
|
op_a_v := (opa(opa'left) and (not ctrl_i(ctrl_alu_unsigned_c))) & opa;
|
op_b_v := (opb(opb'left) and (not ctrl_i(ctrl_alu_unsigned_c))) & opb;
|
op_b_v := (opb(opb'left) and (not ctrl_i(ctrl_alu_unsigned_c))) & opb;
|
|
|
-- add/sub(slt) select --
|
-- add/sub(slt) select --
|
if (ctrl_i(ctrl_alu_addsub_c) = '1') then -- subtraction
|
if (ctrl_i(ctrl_alu_addsub_c) = '1') then -- subtraction
|
op_y_v := not op_b_v;
|
op_y_v := not op_b_v;
|
cin_v(0) := '1';
|
cin_v(0) := '1';
|
else -- addition
|
else -- addition
|
op_y_v := op_b_v;
|
op_y_v := op_b_v;
|
cin_v(0) := '0';
|
cin_v(0) := '0';
|
end if;
|
end if;
|
|
|
-- adder core (result + carry/borrow) --
|
-- adder core (result + carry/borrow) --
|
addsub_res <= std_ulogic_vector(unsigned(op_a_v) + unsigned(op_y_v) + unsigned(cin_v(0 downto 0)));
|
addsub_res <= std_ulogic_vector(unsigned(op_a_v) + unsigned(op_y_v) + unsigned(cin_v(0 downto 0)));
|
end process binary_arithmetic_core;
|
end process binary_arithmetic_core;
|
|
|
-- direct output of address result --
|
-- direct output of address result --
|
Line 225... |
Line 207... |
|
|
-- --------------------------------------------------------------------------------
|
-- --------------------------------------------------------------------------------
|
-- Barrel shifter (huge but fast)
|
-- Barrel shifter (huge but fast)
|
-- --------------------------------------------------------------------------------
|
-- --------------------------------------------------------------------------------
|
else
|
else
|
|
|
-- operands and cycle control --
|
-- operands and cycle control --
|
if (shifter.start = '1') then -- trigger new shift
|
if (shifter.start = '1') then -- trigger new shift
|
shifter.bs_d_in <= rs1_i; -- shift operand (can only be rs1; opa would also contain pc)
|
shifter.bs_d_in <= rs1_i; -- shift operand (can only be rs1; opa would also contain pc)
|
shifter.bs_a_in <= opb(index_size_f(data_width_c)-1 downto 0); -- shift amount
|
shifter.bs_a_in <= opb(index_size_f(data_width_c)-1 downto 0); -- shift amount
|
shifter.cnt <= (others => '0');
|
shifter.cnt <= (others => '0');
|
Line 293... |
Line 274... |
-- shift operation running? --
|
-- shift operation running? --
|
shifter.run <= '1' when (or_all_f(shifter.cnt) = '1') or (shifter.start = '1') else '0';
|
shifter.run <= '1' when (or_all_f(shifter.cnt) = '1') or (shifter.start = '1') else '0';
|
shifter.halt <= '1' when (or_all_f(shifter.cnt(shifter.cnt'left downto 1)) = '1') or (shifter.start = '1') else '0';
|
shifter.halt <= '1' when (or_all_f(shifter.cnt(shifter.cnt'left downto 1)) = '1') or (shifter.start = '1') else '0';
|
|
|
|
|
-- Coprocessor Arbiter --------------------------------------------------------------------
|
-- Co-Processor Arbiter -------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
|
-- Interface:
|
|
-- Co-processor "valid" signal has to be asserted (for one cycle) one cycle before asserting output data
|
|
-- Co-processor "output data" has to be always zero unless co-processor was explicitly triggered
|
cp_arbiter: process(rstn_i, clk_i)
|
cp_arbiter: process(rstn_i, clk_i)
|
begin
|
begin
|
if (rstn_i = '0') then
|
if (rstn_i = '0') then
|
cp_ctrl.cmd_ff <= '0';
|
cp_ctrl.cmd_ff <= '0';
|
cp_ctrl.busy <= '0';
|
cp_ctrl.busy <= '0';
|
Line 324... |
Line 308... |
|
|
-- co-processor operation (still) running? --
|
-- co-processor operation (still) running? --
|
cp_ctrl.halt <= (cp_ctrl.busy and (not (cp0_valid_i or cp1_valid_i or cp2_valid_i or cp3_valid_i))) or cp_ctrl.start;
|
cp_ctrl.halt <= (cp_ctrl.busy and (not (cp0_valid_i or cp1_valid_i or cp2_valid_i or cp3_valid_i))) or cp_ctrl.start;
|
|
|
-- co-processor result --
|
-- co-processor result --
|
cp_read_back: process(clk_i)
|
|
begin
|
|
if rising_edge(clk_i) then
|
|
cp_res <= cp0_data_i or cp1_data_i or cp2_data_i or cp3_data_i; -- only the *actually selected* co-processor may output data != 0
|
cp_res <= cp0_data_i or cp1_data_i or cp2_data_i or cp3_data_i; -- only the *actually selected* co-processor may output data != 0
|
end if;
|
|
end process cp_read_back;
|
|
|
|
|
|
-- ALU Logic Core -------------------------------------------------------------------------
|
-- ALU Logic Core -------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
alu_logic_core: process(ctrl_i, rs1_i, opb)
|
alu_logic_core: process(ctrl_i, rs1_i, opb)
|