So I'm trying to desgin a Processor for a university project and as I was going back to check my code I found out that my ALU unit doens't produce the correct results for addition and subtraction. Can you help me solve this? My code is as follows:
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity ALU_32bit is
Port ( A : in std_logic_vector (31 downto 0);
B : in std_logic_vector (31 downto 0);
ALU_Sel : in std_logic_vector (3 downto 0);
ALU_Out : out std_logic_vector (31 downto 0);
Zero : out std_logic;
Cout : out std_logic;
Ovf : out std_logic);
end ALU_32bit;
architecture Behavioral of ALU_32bit is
signal ALU_result: std_logic_vector(31 downto 0);
signal Total_result:std_logic_vector(32 downto 0) := (others => '0');
signal Carryout, Overflow : std_logic;
begin
process(A, B, ALU_Sel)
begin
case (ALU_Sel) is
when "0000" => --Addition
Total_result <= std_logic_vector(signed('0' & A) + signed('0' & B));
ALU_result <= Total_result(31 downto 0);
Carryout <= Total_result(32);
when "0001" => --Subtraction
Total_result <= std_logic_vector(signed('0' & A) - signed('0' & B));
ALU_result <= Total_result(31 downto 0);
Carryout <= Total_result(32);
when "0010" => --Bitwise AND
ALU_result <= A and B;
when "0011" => --Bitwise OR
ALU_result <= A or B;
when "0100" => --Bitwise NOT
ALU_result <= not A;
when "1000" => --Numerical Right Shift
ALU_result <= std_logic_vector(signed(A) srl 1);
when "1001" => --Logical Right Shift
ALU_result <= std_logic_vector(unsigned(A) srl 1);
when "1010" => --Logical Left Shift
ALU_result <= std_logic_vector(unsigned(A) sll 1);
when "1100" => --Logical Left Rotate
ALU_result <= std_logic_vector(unsigned(A) rol 1);
when "1101" => --Logical Right Rotate
ALU_result <= std_logic_vector(unsigned(A) ror 1);
when others => --Default Case; No opcode
ALU_result <= x"00000000";
end case;
-- Overflow detection for addition
if ((A(31) = '0' and B(31) = '0' and ALU_result(31) = '1') or
(A(31) = '1' and B(31) = '1' and ALU_result(31) = '0'))
then
Overflow <= '1';
else
Overflow <= '0';
end if;
-- Overflow detection for subtraction
if ((A(31) = '0' and B(31) = '0' and Total_result(31) = '1') or
(A(31) = '1' and B(31) = '1' and Total_result(31) = '0'))
then
Overflow <= '1';
else
Overflow <= '0';
end if;
end process;
ALU_Out <= ALU_result;
Zero <= '1' when ALU_result = x"00000000" else '0';
Ovf <= Overflow;
Cout <= Carryout;
end Behavioral;
So for example, when I'm adding the numbers x"00000001" and x"00000001" in the testbench my addition result is x"00000000" and the subtraction result is x"00000010" for some reason.
So the issue to the above code can be resolved by doing the below alterations :
What have I done here instead of the snippet of code above, is that I have removed completely the signal Total_result and instead made a larger by 1 bit Alu_result signal to use for each case and used all 33 bits in addition/subtraction as we need that extra one provided in the signal only for the carryout. All the other operations have been done with using just 32 bits of the signal since that is what is needed. The total_result was just not useful, because it would take one cycle to pass on to ALU_result the correct value of the operations which means that I could lose a result, and skip the next one, while on the waveform I could see that all the other operation results were correct, and that happened because this is a sequential circuit. Completely removing Total_result and just using ALU_result instead is giving me the correct results.
library IEEE; <- this is the library clause that is missing
Here is also a very basic testbench that showcases the correct addition and subtraction.