Skip to content

Instantly share code, notes, and snippets.

@pauljohanneskraft
Last active April 8, 2024 15:45
Show Gist options
  • Save pauljohanneskraft/b3e9d8f27b62200da705b258b63bdd60 to your computer and use it in GitHub Desktop.
Save pauljohanneskraft/b3e9d8f27b62200da705b258b63bdd60 to your computer and use it in GitHub Desktop.
ALU in VHDL

ALU in VHDL

This is an implementation of a 16-bit ALU in VHDL.

Inputs

Name Purpose Size
R, S operands 16-bit integer
I operation 3-bit
cin carry-in 1 bit
clk clock 1 bit
ce determines, whether it should be active or not 1 bit

Outputs

Name Purpose Size
cout Carry-Flag 1 bit
sign Sign-Flag 1 bit
zero Zero-Flag 1 bit
F result 16-bit integer

Operations

Code Operation
000 R + S
001 S - R
010 R - S
011 R OR S
100 R AND S
101 (NOT R) AND S
110 R XOR S
111 R XNOR S
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity alu is
port(
-- inputs:
R, S : in unsigned(15 downto 0); -- operands
I : in std_logic_vector(5 downto 3); -- operation
cin, clk, ce : in std_logic; -- carry in, clock, CE-input (whether component should be active or not)
-- outputs:
cout, sign, zero: out std_logic; -- carry, sign, zero flag
F : out unsigned(15 downto 0) -- result
);
end entity;
architecture calculation of alu is
signal F_i : unsigned(16 downto 0) := "00000000000000000";
-- internal signal for calculation
-- is assigned to F-output and carry-flag with concurrent statement
begin
-- councurrent statements
sign <= F_i(15);
-- sign-flag is determined by bit 15 of the result -> sign bit
zero <= '1' when F_i(15 downto 0) = "0000000000000000" else '0';
-- only setting zero flag if result is zero, so all bits of F have to be 0
F <= F_i(15 downto 0);
-- bits 15 downto 0 will be the result
cout <= F_i(16);
-- bit 16 of F_i is the carry-flag
-- processes
process(clk) is
begin
if rising_edge(clk) and ce = '1' then
-- clk is the clock, ce determines if the alu should be active
case I is
-- determining operation
-- concatenating first when using arithmetic calculations
-- when using logical operations, the carry-flag is always 0
when "000" => -- ADD
if cin = '1' then F_i <= ('0' & R) + ('0' & S) + 1;
else F_i <= ('0' & R) + ('0' & S);
end if;
when "001" => -- SUBR
if cin = '1' then F_i <= ('0' & S) - ('0' & R);
else F_i <= ('0' & S) - ('0' & R) - 1;
end if;
when "010" => -- SUBS
if cin = '1' then F_i <= ('0' & R) - ('0' & S);
else F_i <= ('0' & R) - ('0' & S) - 1;
end if;
-- concatenation happening after calculation because carry flag is impossible to reach
when "011" => F_i <= '0' & (R OR S); -- OR
when "100" => F_i <= '0' & (R AND S); -- AND
when "101" => F_i <= '0' & (NOT R AND S); -- NOTRS
when "110" => F_i <= '0' & (R XOR S); -- XOR
when "111" => F_i <= '0' & (R XNOR S); -- XNOR
when others =>
end case;
end if;
end process;
end architecture;
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity testbench is
end entity;
architecture tb_behavior of testbench is
-- component declarations
component alu is
port(
-- inputs:
R, S : in unsigned(15 downto 0); -- operands
I : in std_logic_vector(5 downto 3); -- which operation should be executed
cin, clk, ce : in std_logic; -- carry in, clock, CE-input (whether component should be active or not)
-- outputs:
cout, sign, zero: out std_logic; -- carry, sign, zero flag
F : out unsigned(15 downto 0) -- result
);
end component;
-- input signals
signal R : unsigned(15 downto 0) := "0101000011010001";
signal S : unsigned(15 downto 0) := "0100001011011111";
signal cin, clk : std_logic := '1';
signal ce : std_logic := '0';
signal I : std_logic_vector(5 downto 3) := "000";
signal eff : std_logic := '1';
-- output signals
signal cout, sign, zero : std_logic;
signal F : unsigned(15 downto 0);
begin
-- concurrent statements
clk <= not clk after 10 ns;
-- clock speed: 50 MHz
cin <= not cin after 240 ns;
-- one effective clock cycle = 160 ns
-- => 3 effective clock cycles = 480 ns
-- => change every 480 second, so that every calculation gets tested with and without carry-in
eff <= not eff after 40 ns;
-- 4 base clock cycles = 1 effective clock cycle
-- processes
process(eff) is
begin
if rising_edge(eff) then
R <= R + 1;
S <= S + 3;
CE <= '0', '1' after 40 ns, '0' after 60 ns;
-- calculation happening in every third base clock cycle
case I is
-- so that every operation is used equally often, just switching to the "next one"
when "000" => I <= "001";
when "001" => I <= "010";
when "010" => I <= "011";
when "011" => I <= "100";
when "100" => I <= "101";
when "101" => I <= "110";
when "110" => I <= "111";
when others => I <= "000";
end case;
end if;
end process;
-- instances
test_alu1 : alu
port map (
-- inputs:
R => R,
S => S,
I => I,
ce => ce,
cin => cin,
clk => clk,
-- outputs:
cout => cout,
sign => sign,
zero => zero,
F => F
);
end architecture;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment