-1

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.

  • @user16145658 I am sorry I added the part about me being depserate for the project, I will edit it out. I understand that you are suggesting that I add for example the testbench that I have created? – DilligentSlacker May 12 '23 at 20:02
  • 1
    See [ask] Provide a [mcve]. Note Total_result is not in the process sensitivity list. Simply adding it in isn't ideal. Consider separating the add/subtract to another process. Latches are created when there are some execution paths that make assignments and some that don't. Your problem can't be reproduced without a minimal, complete, and verifiable example. – user16145658 May 12 '23 at 20:07
  • I resolved the issue by following your advice. I completely removed the Total_result and just did everything with ALU_result by using 33 bits for addition/subtraction and 32 bits for anything else. Now it works. I will use your advice on anyfuture matters, and provide what you requested for to be done in any future questions. – DilligentSlacker May 12 '23 at 20:10
  • 1
    So provide a [mcve] and answer you own question. If it's not a duplicate question it's value to future readers as a search result gets validated by reader up or down votes of both the question and any answers. An explanation as to why the answer works is also useful, otherwise it's just cargo cult design/programming. – user16145658 May 12 '23 at 20:21

1 Answers1

-2

So the issue to the above code can be resolved by doing the below alterations :

..signal ALU_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 
             ALU_result <= std_logic_vector(signed('0' & A) + signed('0' & B));
             Carryout <= ALU_result(32);              
        when "0001" => --Subtraction
          ALU_result(31 downto 0)  <= std_logic_vector(signed('0' & A) - signed('0' & B));
             Carryout <= ALU_result(32);
        when "0010" => --Bitwise AND..

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

USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
 
ENTITY ALU_Testbench IS
END ALU_Testbench;
 
ARCHITECTURE behavior OF ALU_Testbench IS 
  
   --Inputs
   signal tb_A : std_logic_vector(31 downto 0) := (others => '0');
   signal tb_B : std_logic_vector(31 downto 0) := (others => '0');
   signal tb_ALU_Sel : std_logic_vector(3 downto 0) := (others => '0');

    --Outputs
   signal tb_ALU_Out : std_logic_vector(31 downto 0);
   signal tb_Zero : std_logic;
   signal tb_Cout : std_logic;
   signal tb_Ovf : std_logic;
 
BEGIN
 
    -- Instantiate the Unit Under Test (UUT)
   uut: entity work.ALU_32bit(Behavioral) 
    PORT MAP (
          A => tb_A,
          B => tb_B,
          ALU_Sel => tb_ALU_Sel,
          ALU_Out => tb_ALU_Out,
          Zero => tb_Zero,
          Cout => tb_Cout,
          Ovf => tb_Ovf
        ); 


   -- Stimulus process
   stim_proc: process
   begin
   
      tb_A <= x"00000001";
        tb_B <= x"00000001";
                
        
      tb_ALU_Sel <= "0000"; --Addition
        wait for 100 ns;
        
      tb_ALU_Sel <= "0001"; --Subtraction 
        wait for 100 ns;
                
      tb_ALU_Sel <= "0010"; --Bitwise AND
        wait for 100 ns;
                
      tb_ALU_Sel <= "0011"; --Bitwise OR
        wait for 100 ns;
              
        tb_ALU_Sel <= "0100"; --Bitwise NOT
        wait for 100 ns;
              
        tb_ALU_Sel <= "1000"; --Numerical Right Shift
        wait for 100 ns;
              
        tb_ALU_Sel <= "1001"; --Logical Right Shift
        wait for 100 ns;
              
        tb_ALU_Sel <= "1010"; --Logical Left Shift
        wait for 100 ns;
              
        tb_ALU_Sel <= "1100"; --Logical Left Rotate
        wait for 100 ns;
              
        tb_ALU_Sel <= "1101"; --Logical Right Rotate
        wait for 100 ns;
              
        assert false
          report "End"
          severity failure; 
        
   end process;

END;

Here is also a very basic testbench that showcases the correct addition and subtraction.

  • 1
    And yet your readers can still neither replicate the problem nor the solution without a [mcve]. There's also the question of the concurrent signal assignment statement `ALU_Out <= ALU_result;` in the face of the port declaration `ALU_Out : out std_logic_vector (31 downto 0);`. Your answer isn't complete. Your question is missing a library clause and testbench. `Carryout` will have a latch, it's not got an assignment in every process execution path. Total_result(31) has been presumably replaced by ALU_result(31). Your explanation doesn't appear entirely accurate. Test corner cases. – user16145658 May 12 '23 at 22:38