Search code examples
vhdloperations8-bitalu

VHDL: Adding operations to 8-bit ALU


I'm very new to VHDL and am required to modify this ALU with an additional eight operations, which aren't relevant themselves but from the testing in GTKwave I see that the clk(clock) and r(result) discontinue simulating after the first eight operations it seems, although the op waveform acknowledges them. Both source and test bench compile fine with no errors, resulting what seems to be incorrect waveforms. Waveforms/Testing

I tried to fix this by going back into the test bench code and changing the ‘exit L1 when i >10;’ loop from 10 to 20(or any other over 10) and then recompiling, but this resulted in a “bound check failure” error which stumped me. I also tried changing modifying to make it 16-bit, but that didn't compile - definitely not the solution I imagine.

Ignore the mixed up operational comments.

Any help would be much appreciated, I'm assume it's a very novice overlook.

Initial code derived from http://vhdlguru.blogspot.co.uk/2011/06/vhdl-code-for-simple-alu.html

SOURCE CODE

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity Ex8 is
port(   Clk : in std_logic;             --clock signal
        A,B : in signed(7 downto 0);    --input operands
        Op : in unsigned(3 downto 0);   --Operation to be performed -- 2 to 3
        R : out signed(7 downto 0)      --output of ALU
        );
end Ex8;

architecture Behavioral of Ex8 is

--temporary signal declaration.
signal Reg1,Reg2,Reg3 : signed(7 downto 0) := (others => '0');

begin

Reg1 <= A;
Reg2 <= B;
R <= Reg3;

process(Clk)
begin

if(rising_edge(Clk)) then --Do the calculation at the positive edge of clock cycle.
    case Op is
        when "0000" =>
            Reg3 <= Reg1 + Reg2;    --addition
        when "0001" =>
            Reg3 <= Reg1 - Reg2;    --subtraction
        when "0010" =>
            Reg3 <= not Reg1;       --NOT gate
        when "0011" =>
            Reg3 <= Reg1 nand Reg2; --NAND gate
        when "0100" =>
            Reg3 <= Reg1 nor Reg2;  --NOR gate
        when "0101" =>
            Reg3 <= Reg1 and Reg2;  --AND gate
        when "0110" =>
            Reg3 <= Reg1 or Reg2;   --OR gate
        when "0111" =>
            Reg3 <= Reg1 xor Reg2;  --XOR gate
        when "1000" =>
            Reg3 <= Reg1 / Reg2;    --division
        when "1001" =>
            Reg3 <= Reg1 * Reg2;    --multiplication
        when "1010" =>
            Reg3 <= Reg1 xnor Reg2; --rotate left
        when "1011" =>
            Reg3 <= Reg1 srl 4;     --rotate right
        when "1100" =>
            Reg3 <= Reg1 & Reg2;    --shift left logical
        when "1101" =>
            Reg3 <= Reg1 sll 4;     --shift right logical
        when "1110" =>
            Reg3 <= Reg1 mod Reg2;  --modulo
        when "1111" =>
            Reg3 <= Reg1 rem Reg2;  --remainder

        when others =>
            NULL;

       end case;
    end if;
end process;
end Behavioral;

TEST BENCH

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;

ENTITY Ex8_tb IS
END Ex8_tb;

ARCHITECTURE behavior OF Ex8_tb IS

   signal Clk : std_logic := '0';
   signal A,B,R : signed(7 downto 0) := (others => '0');
   signal Op : unsigned(3 downto 0) := (others => '0');
   constant Clk_period : time := 10 ns;

BEGIN

            -- Instantiate the Unit Under Test (UUT)
   uut: entity work.Ex8 PORT MAP (
          Clk => Clk,
          A => A,
          B => B,
          Op => Op,
          R => R
        );

        -- Clock process definitions
   Clk_process :process
   variable i : POSITIVE := 1;
   begin
        L1: loop
        Clk <= '0';
        wait for Clk_period/2;
        Clk <= '1';
        wait for Clk_period/2;
        i:= i+1;
        exit L1 when i >10;
        end loop L1;                -- changed from failure to warning
        assert false report "NONE. End of simulation." severity warning;  
        wait;                   -- added wait;
   end process;

-- Stimulus process
   stim_proc: process
   begin
      wait for Clk_period*1;
        A <= "00010010";                        --18 in decimal
        B <= "00001010";                        --10 in decimal
        Op <= "0000";  wait for Clk_period;     --add A and B
        Op <= "0001";  wait for Clk_period;     --subtract B from A.
        Op <= "0010";  wait for Clk_period;     --Bitwise NOT of A
        Op <= "0011";  wait for Clk_period;     --Bitwise NAND of A and B
        Op <= "0100";  wait for Clk_period;     --Bitwise NOR of A and B
        Op <= "0101";  wait for Clk_period;     --Bitwise AND of A and B  
        Op <= "0110";  wait for Clk_period;     --Bitwise OR of A and B
        Op <= "0111";  wait for Clk_period;     --Bitwise XOR of A and B
        Op <= "1000";  wait for Clk_period;     --Bitwise DIV of A and B
        Op <= "1001";  wait for Clk_period;     --Bitwise MUL of A and B
        Op <= "1010";  wait for Clk_period;     --Bitwise ROL of A and B
        Op <= "1011";  wait for Clk_period;     --Bitwise ROR of A and B
        Op <= "1100";  wait for Clk_period;     --Bitwise SLL of A and B
        Op <= "1101";  wait for Clk_period;     --Bitwise SRL of A and B
        Op <= "1110";  wait for Clk_period;     --Bitwise MOD of A and B
        Op <= "1111";  wait for Clk_period;     --Bitwise REM of A and B
      wait;
   end process;

END;

Solution

  • You have one problem in your code that prevents it compiling; you have one that prevents it simulating (a run-time error). Both fail for the same reason: array sizes do not match.

    This line might not compile:

    Reg3 <= Reg1 & Reg2;
    

    This is because reg1, reg2 and reg3 are all the same width. & is concatenation - the joining of two arrays to make a bigger array. The width of reg3 needs to be equal to the width of reg1 plus the width of reg2. (I say "might not" because it gave a compile error on one simulator and a runtime error on another).

    I then changed this line:

    exit L1 when i >10;
    

    to this:

    exit L1 when i >20;
    

    as you suggested and then got a run time error at this line:

    Reg3 <= Reg1 * Reg2;    --multiplication
    

    This is again because reg1, reg2 and reg3 are all the same width. The multiplication operator defined in the numeric_std package outputs a result with width equal to the sum of the widths of the two operands, ie the width of reg1 plus the width of reg2.

    So, you need to think about the widths of your inputs and outputs or you need to do some truncation (but that would make your concatenation operation pointless).