Search code examples
vhdlbit

VHDL adder, same word length?


In VHDL i want to add a number of 5 bits and a number of 8 bits.(Unsigned) And how many bits does the output have?

I want my code to answer the questions i just asked. My code currently look like this...

My code is:

library ieee;
use ieee-std_logic_1164.all;
entity adder is
port( a : in unsigned (7 downto 0);
         b : in unsigned (4 downto 0); - - Need to convert this to 8 bit right? But how?
         z : out unsigned(7 downto 0)); - - This one must be  8 bits right? Cuz a & b & z must have the same WL. Or am i wrong?

end adder;

archictecture add of adder is 
begin 
z <= a + b;
end archictecture;

Solution

  • In package numeric_std for function "+" (L, R: UNSIGNED) return UNSIGNED the length of the longest argument defines the return value length:

      function "+" (L, R: UNSIGNED) return UNSIGNED is
        constant SIZE: NATURAL := MAX(L'LENGTH, R'LENGTH);
        variable L01 : UNSIGNED(SIZE-1 downto 0);
        variable R01 : UNSIGNED(SIZE-1 downto 0);
      begin
        if ((L'LENGTH < 1) or (R'LENGTH < 1)) then return NAU;
        end if;
        L01 := TO_01(RESIZE(L, SIZE), 'X');
        if (L01(L01'LEFT)='X') then return L01;
        end if;
        R01 := TO_01(RESIZE(R, SIZE), 'X');
        if (R01(R01'LEFT)='X') then return R01;
        end if;
        return ADD_UNSIGNED(L01, R01, '0');
      end "+";
    

    The maximum of the left and right arguments length is SIZE, the range of the two arguments is is resized to SIZE -1 downto 0 as arguments to ADD_UNSIGNED.

      function ADD_UNSIGNED (L, R: UNSIGNED; C: STD_LOGIC) return UNSIGNED is
        constant L_LEFT: INTEGER := L'LENGTH-1;
        alias XL: UNSIGNED(L_LEFT downto 0) is L;
        alias XR: UNSIGNED(L_LEFT downto 0) is R;
        variable RESULT: UNSIGNED(L_LEFT downto 0);
        variable CBIT: STD_LOGIC := C;
      begin
        for I in 0 to L_LEFT loop
          RESULT(I) := CBIT xor XL(I) xor XR(I);
          CBIT := (CBIT and XL(I)) or (CBIT and XR(I)) or (XL(I) and XR(I));
        end loop;
        return RESULT;
      end ADD_UNSIGNED;
    

    The RESULT's length is that of the L argument which is the same of both arguments to UNSIGNED_ADD. There is no carry out implied in the result.

    As in your case the result, assigned to z can be 8 bits.

    Fix the comment delimiters in the port declarations, add a use clause to access package numeric_std, fix a '-' that should be a '.', spelling of architecture and add a test bench adding values for a and b set to all '1's and you can analyze, elaborate and run your design without error, telling you there isn't an array length error executing.

    To get that ninth 'bit' as an output of the adder you can RESIZE one of your arguments to + to 9 bits or concatenate one argument with leading zeros to make a 9 bit value:

        z <= "0" & a + b;
    

    It'll demonstrate that the 9th bit is needed for an accurate result:

    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;
    
    entity adder is
        port( 
            a: in  unsigned (7 downto 0);
            b: in  unsigned (4 downto 0); 
            z: out unsigned (8 downto 0)
        ); 
    end adder;
    
    architecture add of adder is 
    begin 
        z <= "0" & a + b;
    end architecture;
    
    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;
    
    entity tb_adder is 
    end entity;
    
    architecture foo of tb_adder is
        signal a: unsigned (7 downto 0) := (others => '1');
        signal b: unsigned (4 downto 0) := (others => '1');
        signal z: unsigned (8 downto 0);
    
        function unsigned_image(inp: unsigned) return string is
            variable image_str: string (1 to inp'length);
            alias input_str:  unsigned (1 to inp'length) is inp;
        begin
            for i in input_str'range loop
                image_str(i) := character'VALUE(std_ulogic'IMAGE(input_str(i)));
            end loop;
            return image_str;
        end;
    
    begin
    
    DUT: 
        entity work.adder
            port map (
                a => a,
                b => b,
                z => z
            );
    
    MONITOR:
        process 
        begin
            wait for 1 ns;
            report "z = " & unsigned_image(z);
            wait;
        end process;
    
    end architecture;
    

    david_koontz@Macbook: ghdl -a adder.vhdl
    david_koontz@Macbook: ghdl -e tb_adder
    david_koontz@Macbook: ghdl -r tb_adder
    adder.vhdl:54:9:@1ns:(report note): z = 100011110