Search code examples
type-conversionvhdlunsignedalu

Trouble implementing unsigned component to conditions of ALU in VHDL


I have to create an ALU that has conditions for add, add unsigned, sub, sub unsigned, and, or, xor, nor, slt, and slt unsigned. I am having difficulty implementing the design to include the unsigned conditions. I have noted in the code where the errors are occurring. Also, every other aspect of the ALU works correct, it is ONLY the unsigned portion I need help with. I was researching about unsigned and std_logic but I was unable to find the problems similar to mine.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use ieee.NUMERIC_STD.all;

entity ALU is
Port (A, B     : in  STD_LOGIC_VECTOR (31 downto 0);
      ALUCntl  : in  STD_LOGIC_VECTOR (3 downto 0);
      Carryin  : in  STD_LOGIC;
      ALUOut   : out STD_LOGIC_VECTOR (31 downto 0);
      Zero     : out STD_LOGIC;
      Carryout : out STD_LOGIC;
      Overflow : out STD_LOGIC);
end ALU; 


architecture Behavioral of ALU is
signal ALU_Result, slt, sltu : std_logic_vector (31 downto 0);
signal add_result,sub_result,a32,b32: std_logic_vector(32 downto 0);
-- create separate a and b for unsigned 
signal add_u,sub_u,a32u,b32u: unsigned(32 downto 0);
signal c32: std_logic_vector(32 downto 0):=(others=>'0');
signal add_ov,sub_ov:std_logic;

begin
with ALUCntl select
ALU_Result <=add_result(31 downto 0) when "0010", -- add
            sub_result(31 downto 0) when "0110", -- sub
            slt     when "0111", -- set less than
            std_logic_vector(add_u(31 downto 0)) when "0100", -- add unsigned 
            std_logic_vector(sub_u(31 downto 0)) when "0101", -- sub unsigned
            sltu    when "1000", -- set less than unsigned
            A AND B when "0000",
            A OR  B when "0001",
            A XOR B when "0011",
            A NOR B when "1100",
            A when others;---condition for all other alu control signals
ALUOut  <= ALU_Result; 
----Set less than-----------------------------------
process(a32,b32)
begin
if (a32 < b32) then 
    slt <= x"00000001";
else
    slt <= x"00000000";
end if;
end process;
process(a32u,b32u)
begin
if (a32u < b32u) then 
    sltu <= x"00000001";
else
    sltu <= x"00000000";
end if;
end process;
----Addition Operation and carry out generation-----    
a32   <='0'& A;
b32   <='0'& B;
c32(0)<=Carryin;
add_result<=std_logic_vector(signed(a32) + signed(b32) + signed(c32));
sub_result<=std_logic_vector(signed(a32) - signed(b32));

a32u   <=unsigned('0'& A);
b32u   <=unsigned('0'& B);
add_u<=a32u + b32u + unsigned(c32);
sub_u<=a32u - b32u;

---Zero flag-----------------------------   
Zero <= '1' when ALU_Result =x"00000000" else '0';

---Overflow flag---------------------------------------
add_ov<= (A(31)and B(31)       and (not alu_result(31))) or ((not A(31))and (not B(31)) and alu_result(31));
sub_ov<= (A(31)and (not B(31)) and (not alu_result(31))) or ((not A(31))and B(31)       and alu_result(31)); 
with ALUCntl select
  Overflow<= add_ov when "0010" | "0100",
             sub_ov when "0110" | "0101",
             'Z' when others;

---Carryout-------------------------------------------------
With ALUCntl select 
Carryout<= add_result(32) when "0010",
            sub_result(32) when "0110",
            add_u(32)      when "0100",
            sub_u(32)      when "0101",
            'Z' when others;
end Behavioral;

Solution

  • I've gone through it thoroughly. The main issue is type conversions, so I've commented where I've added them. I've also tweaked some of the code to make it more readable by adding constants for the command names which is generally good practice, and a case statement for command selection. And std_logic_unsigned is a deprecated non standard library.

    I've updated it in keeping with your updates to your original question regarding the processing of unsigned logic. I've also added a couple more constants and three subtypes in keeping with the design principle of only having one version of the truth.

    library ieee;
    use ieee.std_logic_1164.all;
    --use ieee.std_logic_unsigned.all;  -- Not advisable to use this non standard library.
    use ieee.numeric_std.all;
    
    entity ALU is
        generic
        (
            ALU_BITS: natural := 32  -- Added a generic parameter to specify the number of bits in the ALU.
        );
        port
        (
            A, B     : in  std_logic_vector (ALU_BITS - 1 downto 0);
            ALUCntl  : in  std_logic_vector (3 downto 0);
            Carryin  : in  std_logic;
            ALUOut   : out std_logic_vector (ALU_BITS - 1 downto 0);
            Zero     : out std_logic;
            Carryout : out std_logic;
            Overflow : out std_logic
        );
    end ALU;
    
    architecture Behavioral of ALU is
    
        -- Added some constants and subtypes to make the code more readable and maintainable.
    
        constant ALU_MSB: natural := ALU_BITS - 1;
    
        subtype TALURegister is std_logic_vector(ALU_MSB downto 0);
        subtype TALURegisterX is std_logic_vector(ALU_BITS downto 0);
        subtype TALURegisterXU is unsigned(ALU_BITS downto 0);
    
        constant ALU_REGISTER_ZERO: TALURegister := (others => '0');
        constant ALU_REGISTER_ONE : TALURegister := (ALU_MSB downto 1 => '0') & '1';
    
        constant CMD_ADD   : std_logic_vector := "0010";
        constant CMD_SUB   : std_logic_vector := "0110";
        constant CMD_SLT   : std_logic_vector := "0111";
        constant CMD_SLT_U : std_logic_vector := "1000";
        constant CMD_ADD_U : std_logic_vector := "0100";
        constant CMD_SUB_U : std_logic_vector := "0101";
        constant CMD_AND   : std_logic_vector := "0000";
        constant CMD_OR    : std_logic_vector := "0001";
        constant CMD_XOR   : std_logic_vector := "0011";
        constant CMD_NOR   : std_logic_vector := "1100";
    
        signal ALU_Result, slt, sltu : TALURegister;
        signal add_result, sub_result, a32, b32: TALURegisterX;
    
        -- create separate a and b for unsigned
        signal add_u, sub_u, a32u, b32u: TALURegisterXU;
        signal c32: TALURegisterX := (others => '0');
        signal add_ov, sub_ov: std_logic;
    
        begin
            -- Alternative command selection using a case statement.
            process(ALUCntl, add_result, sub_result, slt, sltu, add_u, sub_u, A, B)
            begin
                case ALUCntl is
                    when CMD_ADD    =>  ALU_Result <= add_result(ALU_MSB downto 0);
                    when CMD_SUB    =>  ALU_Result <= sub_result(ALU_MSB downto 0);
                    when CMD_SLT    =>  ALU_Result <= slt;
                    when CMD_SLT_U  =>  ALU_Result <= sltu;
                    when CMD_ADD_U  =>  ALU_Result <= TALURegister(add_u(ALU_MSB downto 0));  -- Added type conversion.
                    when CMD_SUB_U  =>  ALU_Result <= TALURegister(sub_u(ALU_MSB downto 0));  -- Added type conversion.
                    when CMD_AND    =>  ALU_Result <= A and B;
                    when CMD_OR     =>  ALU_Result <= A or B;
                    when CMD_XOR    =>  ALU_Result <= A xor B;
                    when CMD_NOR    =>  ALU_Result <= A nor B;
                    when others     =>  ALU_Result <= A;
                end case;
            end process;
    
            -- with ALUCntl select
                -- ALU_Result <=
                    -- add_result(ALU_MSB downto 0) when CMD_ADD, -- add
                    -- sub_result(ALU_MSB downto 0) when CMD_SUB, -- sub
                    -- slt     when CMD_SLT, -- set less than
    
                    -- - Getting an error that indexed name is not STD_LOGIC_VECTOR --
                    -- TALURegister(add_u(ALU_MSB downto 0)) when CMD_ADD_U, -- add unsigned  -- Added type conversion.
                    -- TALURegister(sub_u(ALU_MSB downto 0)) when CMD_SUB_U, -- sub unsigned  -- Added type conversion.
                    ---------------------------------------------------------
    
                    -- sltu    when CMD_SLT_U, -- set less than unsigned
                    -- A AND B when CMD_AND,
                    -- A OR  B when CMD_OR,
                    -- A XOR B when CMD_XOR,
                    -- A NOR B when CMD_NOR,
                    -- A when others;---condition for all other alu control signals
    
            ALUOut  <= ALU_Result;
    
            ----Set less than-----------------------------------
            process(a32, b32)
            begin
                if (a32 < b32) then
                    slt <= ALU_REGISTER_ONE;
                else
                    slt <= ALU_REGISTER_ZERO;
                end if;
            end process;
    
            ----Set less than unsigned--------------------------
            process(a32u, b32u)
            begin
            if (a32u < b32u) then
                sltu <= ALU_REGISTER_ONE;
            else
                sltu <= ALU_REGISTER_ZERO;
            end if;
            end process;
    
            ----Addition Operation and carry out generation-----
            a32     <= '0' & A;
            b32     <= '0' & B;
            c32(0)  <= Carryin;
            add_result <= TALURegisterX(signed(a32) + signed(b32) + signed(c32));  -- Added type conversion.
            sub_result <= TALURegisterX(signed(a32) - signed(b32));                -- Added type conversion.
    
            -- Getting "'0' definitions found" errors here --
            a32u  <= TALURegisterXU('0' & A);            -- Added type conversion.
            b32u  <= TALURegisterXU('0' & B);            -- Added type conversion.
            add_u <= a32u + b32u + TALURegisterXU(c32);  -- Added type conversion.
            sub_u <= a32u - b32u;
    
            -------------------------------------------------
            ---Zero flag-----------------------------
            Zero <= '1' when ALU_Result = ALU_REGISTER_ZERO else '0';
    
            ---Overflow flag---------------------------------------
            add_ov <= (A(ALU_MSB) and B(ALU_MSB)       and (not alu_result(ALU_MSB))) or ((not A(ALU_MSB)) and (not B(ALU_MSB)) and alu_result(ALU_MSB));
            sub_ov <= (A(ALU_MSB) and (not B(ALU_MSB)) and (not alu_result(ALU_MSB))) or ((not A(ALU_MSB)) and B(ALU_MSB)       and alu_result(ALU_MSB));
            with ALUCntl select
                Overflow <=
                    add_ov when CMD_ADD | CMD_ADD_U,
                    sub_ov when CMD_SUB | CMD_SUB_U,
                    'Z' when others;
    
            ---Carryout-------------------------------------------------
            with ALUCntl select
                Carryout <=
                    add_result(ALU_BITS) when CMD_ADD,
                    sub_result(ALU_BITS) when CMD_SUB,
                    add_u(ALU_BITS)      when CMD_ADD_U,
                    sub_u(ALU_BITS)      when CMD_SUB_U,
                    'Z' when others;
    end Behavioral;