RPU/vhdl/unit_alu_RV32_I.vhd

215 lines
No EOL
6.9 KiB
VHDL

----------------------------------------------------------------------------------
-- Project Name: RISC-V CPU
-- Description: ALU unit suitable for RV32I operational use
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
library work;
use work.constants.all;
entity alu_RV32I is
Port (
I_clk : in STD_LOGIC;
I_en : in STD_LOGIC;
I_dataA : in STD_LOGIC_VECTOR (XLEN32M1 downto 0);
I_dataB : in STD_LOGIC_VECTOR (XLEN32M1 downto 0);
I_dataDwe : in STD_LOGIC;
I_aluop : in STD_LOGIC_VECTOR (4 downto 0);
I_aluFunc : in STD_LOGIC_VECTOR (15 downto 0);
I_PC : in STD_LOGIC_VECTOR (XLEN32M1 downto 0);
I_dataIMM : in STD_LOGIC_VECTOR (XLEN32M1 downto 0);
O_dataResult : out STD_LOGIC_VECTOR (XLEN32M1 downto 0);
O_branchTarget : out STD_LOGIC_VECTOR (XLEN32M1 downto 0);
O_dataWriteReg : out STD_LOGIC;
O_shouldBranch : out std_logic
);
end alu_RV32I;
architecture Behavioral of alu_RV32I is
-- The internal register for results of operations.
-- 32 bit + carry/overflow
signal s_branchTarget : STD_LOGIC_VECTOR (XLEN32M1 downto 0) := (others => '0');
signal s_result: STD_LOGIC_VECTOR(XLEN32M1+2 downto 0) := (others => '0');
signal s_shouldBranch: STD_LOGIC := '0';
begin
process (I_clk, I_en)
begin
if rising_edge(I_clk) and I_en = '1' then
O_dataWriteReg <= I_dataDwe;
case I_aluop is
when OPCODE_OPIMM =>
s_shouldBranch <= '0';
case I_aluFunc(2 downto 0) is
when F3_OPIMM_ADDI =>
s_result(31 downto 0) <= std_logic_vector(signed( I_dataA) + signed( I_dataIMM));
when F3_OPIMM_XORI =>
s_result(31 downto 0) <= I_dataA xor I_dataIMM;
when F3_OPIMM_ORI =>
s_result(31 downto 0) <= I_dataA or I_dataIMM;
when F3_OPIMM_ANDI =>
s_result(31 downto 0) <= I_dataA and I_dataIMM;
when F3_OPIMM_SLTI =>
if signed(I_dataA) < signed(I_dataIMM) then
s_result(31 downto 0) <= X"00000001";
else
s_result(31 downto 0) <= X"00000000";
end if;
when F3_OPIMM_SLTIU =>
if unsigned(I_dataA) < unsigned(I_dataIMM) then
s_result(31 downto 0) <= X"00000001";
else
s_result(31 downto 0) <= X"00000000";
end if;
when F3_OPIMM_SLLI =>
s_result(31 downto 0) <= std_logic_vector(shift_left(unsigned(I_dataA), to_integer(unsigned(I_dataIMM(4 downto 0)))));
when F3_OPIMM_SRLI =>
case I_aluFunc(9 downto 3) is
when F7_OPIMM_SRLI =>
s_result(31 downto 0) <= std_logic_vector(shift_right(unsigned(I_dataA), to_integer(unsigned(I_dataIMM(4 downto 0)))));
when F7_OPIMM_SRAI =>
s_result(31 downto 0) <= std_logic_vector(shift_right(signed(I_dataA), to_integer(unsigned(I_dataIMM(4 downto 0)))));
when others=>
end case;
when others =>
end case;
when OPCODE_OP =>
case I_aluFunc(9 downto 0) is
when F7_OP_ADD & F3_OP_ADD =>
s_result(31 downto 0) <= std_logic_vector(signed( I_dataA) + signed( I_dataB));
when F7_OP_SUB & F3_OP_SUB =>
s_result(31 downto 0) <= std_logic_vector(signed( I_dataA) - signed( I_dataB));
when F7_OP_SLT & F3_OP_SLT =>
if signed(I_dataA) < signed(I_dataB) then
s_result(31 downto 0) <= X"00000001";
else
s_result(31 downto 0) <= X"00000000";
end if;
when F7_OP_SLTU & F3_OP_SLTU =>
if unsigned(I_dataA) < unsigned(I_dataB) then
s_result(31 downto 0) <= X"00000001";
else
s_result(31 downto 0) <= X"00000000";
end if;
when F7_OP_XOR & F3_OP_XOR =>
s_result(31 downto 0) <= I_dataA xor I_dataB;
when F7_OP_OR & F3_OP_OR =>
s_result(31 downto 0) <= I_dataA or I_dataB;
when F7_OP_AND & F3_OP_AND =>
s_result(31 downto 0) <= I_dataA and I_dataB;
when F7_OP_SLL & F3_OP_SLL =>
s_result(31 downto 0) <= std_logic_vector(shift_left(unsigned(I_dataA), to_integer(unsigned(I_dataB(4 downto 0)))));
when F7_OP_SRL & F3_OP_SRL =>
s_result(31 downto 0) <= std_logic_vector(shift_right(unsigned(I_dataA), to_integer(unsigned(I_dataB(4 downto 0)))));
when F7_OP_SRA & F3_OP_SRA =>
s_result(31 downto 0) <= std_logic_vector(shift_right(signed(I_dataA), to_integer(unsigned(I_dataB(4 downto 0)))));
when others=>
s_result <= "00" & X"CDC1FEF1";
end case;
s_shouldBranch <= '0';
when OPCODE_LOAD | OPCODE_STORE =>
s_shouldBranch <= '0';
s_result(31 downto 0) <= std_logic_vector(signed( I_dataA) + signed( I_dataIMM));
when OPCODE_JALR =>
s_branchTarget <= std_logic_vector(signed( I_dataA) + signed( I_dataIMM));
s_shouldBranch <= '1';
s_result(31 downto 0) <= std_logic_vector(signed( I_PC) + 4);
when OPCODE_JAL =>
s_branchTarget <= std_logic_vector(signed( I_PC) + signed( I_dataIMM));
s_shouldBranch <= '1';
s_result(31 downto 0) <= std_logic_vector(signed( I_PC) + 4);
when OPCODE_LUI =>
s_shouldBranch <= '0';
s_result(31 downto 0) <= I_dataIMM;
when OPCODE_AUIPC =>
s_shouldBranch <= '0';
s_result(31 downto 0) <= std_logic_vector( signed( I_PC) + signed( I_dataIMM));
when OPCODE_BRANCH =>
s_branchTarget <= std_logic_vector(signed( I_PC) + signed( I_dataIMM));
case I_aluFunc(2 downto 0) is
when F3_BRANCH_BEQ =>
if I_dataA = I_dataB then
s_shouldBranch <= '1';
else
s_shouldBranch <= '0';
end if;
when F3_BRANCH_BNE =>
if I_dataA /= I_dataB then
s_shouldBranch <= '1';
else
s_shouldBranch <= '0';
end if;
when F3_BRANCH_BLT =>
if signed(I_dataA) < signed(I_dataB) then
s_shouldBranch <= '1';
else
s_shouldBranch <= '0';
end if;
when F3_BRANCH_BGE =>
if signed(I_dataA) >= signed(I_dataB) then
s_shouldBranch <= '1';
else
s_shouldBranch <= '0';
end if;
when F3_BRANCH_BLTU =>
if unsigned(I_dataA) < unsigned(I_dataB) then
s_shouldBranch <= '1';
else
s_shouldBranch <= '0';
end if;
when F3_BRANCH_BGEU =>
if unsigned(I_dataA) >= unsigned(I_dataB) then
s_shouldBranch <= '1';
else
s_shouldBranch <= '0';
end if;
when others =>
end case;
when others =>
s_result <= "00" & X"CDCDFEFE";
end case;
end if;
end process;
O_dataResult <= s_result(XLEN32M1 downto 0);
O_shouldBranch <= s_shouldBranch;
O_branchTarget <= s_branchTarget;
end Behavioral;