Combinational Logic Design

Rules for combinational processes:

Include all read signals in the sensitivity list (or use process(all)).

Assign every output in every path (use defaults) — otherwise you infer latches.

No clock edges, no feedback loops.

12.1 Multiplexer (4:1, generic width)

entity mux4 is
  generic (WIDTH : positive := 8);
  port (
    a, b, c, d : in  std_logic_vector(WIDTH-1 downto 0);
    sel        : in  std_logic_vector(1 downto 0);
    y          : out std_logic_vector(WIDTH-1 downto 0));
end entity;

architecture rtl of mux4 is
begin
  with sel select
    y <= a when "00", b when "01", c when "10", d when others;
end architecture;

12.2 Decoder (3-to-8) and encoder

process (all)
begin
  y <= (others => '0');
  if en = '1' then
    y(to_integer(unsigned(sel))) <= '1';
  end if;
end process;

-- Priority encoder (8-to-3)
process (all)
begin
  code  <= "000";
  valid <= '0';
  for i in 0 to 7 loop          -- later iterations override earlier ones → highest index wins
    if req(i) = '1' then
      code  <= std_logic_vector(to_unsigned(i, 3));
      valid <= '1';
    end if;
  end loop;
end process;

12.3 Ripple-carry adder (structural idea) & behavioral adder

-- Behavioral (preferred — synthesis maps to fast carry chains)
sum <= std_logic_vector(resize(unsigned(a), N+1) + resize(unsigned(b), N+1) + unsigned'(0 => cin));

-- Explicit ripple-carry with a generate loop
carry(0) <= cin;
gen_fa : for i in 0 to N-1 generate
  s(i)       <= a(i) xor b(i) xor carry(i);
  carry(i+1) <= (a(i) and b(i)) or (carry(i) and (a(i) xor b(i)));
end generate;
cout <= carry(N);

12.4 ALU

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity alu is
  generic (N : positive := 8);
  port (
    a, b   : in  std_logic_vector(N-1 downto 0);
    op     : in  std_logic_vector(2 downto 0);
    result : out std_logic_vector(N-1 downto 0);
    zero   : out std_logic;
    carry  : out std_logic);
end entity;

architecture rtl of alu is
begin
  process (all)
    variable ua, ub : unsigned(N downto 0);
    variable r      : unsigned(N downto 0);
  begin
    ua := resize(unsigned(a), N+1);
    ub := resize(unsigned(b), N+1);
    case op is
      when "000" => r := ua + ub;                         -- ADD
      when "001" => r := ua - ub;                         -- SUB
      when "010" => r := ua and ub;                       -- AND
      when "011" => r := ua or ub;                        -- OR
      when "100" => r := ua xor ub;                       -- XOR
      when "101" => r := '0' & not ua(N-1 downto 0);      -- NOT A
      when "110" => r := shift_left(ua, 1);               -- SHL
      when others => r := shift_right(ua, 1);             -- SHR
    end case;
    result <= std_logic_vector(r(N-1 downto 0));
    carry  <= r(N);
    zero   <= '1' when r(
…

12.5 Other combinational blocks

Comparators, barrel shifters, seven-segment decoders, binary↔BCD converters, Gray code converters (g <= b xor ('0' & b(N-1 downto 1))), population count, leading-zero counters, parity generators, multipliers.

12.6 Seven-segment decoder

process (all)
begin
  case digit is              -- segments "gfedcba", active low
    when x"0" => seg <= "1000000";
    when x"1" => seg <= "1111001";
    when x"2" => seg <= "0100100";
    when x"3" => seg <= "0110000";
    when x"4" => seg <= "0011001";
    when x"5" => seg <= "0010010";
    when x"6" => seg <= "0000010";
    when x"7" => seg <= "1111000";
    when x"8" => seg <= "0000000";
    when x"9" => seg <= "0010000";
    when x"A" => seg <= "0001000";
    when x"B" => seg <= "0000011";
    when x"C" => seg <= "1000110";
    when x"D" => seg <= "0100001";
    when x"E" => seg <= "0000110";
    when others => seg <= "0001110";   -- F
  end case;
end process;