End-of-Unit Problems: Introduction to VHDL
Work through these problems to reinforce your understanding of VHDL entities, architectures, concurrent and sequential statements, and synthesis inference.
Section A: Entity and Architecture (4 problems)
Problem 1
Write a complete VHDL entity declaration for a 4-bit magnitude comparator with two 4-bit inputs \(A\) and \(B\), and three single-bit outputs: gt (greater than), eq (equal), and lt (less than). Use std_logic and std_logic_vector types.
Show Solution
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity mag_compare4 is
port (
A : in std_logic_vector(3 downto 0);
B : in std_logic_vector(3 downto 0);
gt : out std_logic;
eq : out std_logic;
lt : out std_logic
);
end entity mag_compare4;
architecture dataflow of mag_compare4 is
begin
gt <= '1' when (A > B) else '0';
eq <= '1' when (A = B) else '0';
lt <= '1' when (A < B) else '0';
end architecture dataflow;
Problem 2
Explain the nine values of the std_logic type. For each value, state what real-world condition it models and whether it is synthesizable.
Show Solution
Problem 3
Given the following VHDL code, identify and correct all syntax errors:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL
entity half_adder is
port (
A, B : in std_logic
sum : out std_logic;
cout : out std_logic;
)
end half_adder;
architecture behave of half_addr is
begin
sum <= A xor B;
cout <= A and B;
end behave;
Show Solution
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity half_adder is
port (
A, B : in std_logic;
sum : out std_logic;
cout : out std_logic
);
end entity half_adder;
architecture behave of half_adder is
begin
sum <= A xor B;
cout <= A and B;
end architecture behave;
Problem 4
Write an entity and architecture for a generic N-bit register with parallel load enable and asynchronous reset. Use the generic clause to make the width parameterizable.
Show Solution
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity reg_n is
generic (
N : positive := 8 -- default width is 8 bits
);
port (
clk : in std_logic;
rst : in std_logic; -- async reset
load : in std_logic; -- load enable
d_in : in std_logic_vector(N-1 downto 0); -- parallel data in
q_out : out std_logic_vector(N-1 downto 0) -- parallel data out
);
end entity reg_n;
architecture behavioral of reg_n is
begin
process(clk, rst)
begin
if rst = '1' then
q_out <= (others => '0'); -- clear all bits
elsif rising_edge(clk) then
if load = '1' then
q_out <= d_in; -- load new data
end if;
-- if load='0', q_out retains value (register holds)
end if;
end process;
end architecture behavioral;
reg16: entity work.reg_n
generic map (N => 16)
port map (
clk => sys_clk,
rst => sys_rst,
load => ld_enable,
d_in => data_bus,
q_out => reg_output
);
Section B: Concurrent Statements and Dataflow (4 problems)
Problem 5
Write a VHDL dataflow architecture for a 2-to-4 decoder with an enable input. The decoder has a 2-bit input sel, 1-bit en, and 4-bit output y. When en = '0', all outputs are '0'.
Show Solution
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity decoder2to4 is
port (
sel : in std_logic_vector(1 downto 0);
en : in std_logic;
y : out std_logic_vector(3 downto 0)
);
end entity decoder2to4;
architecture dataflow of decoder2to4 is
begin
y <= "0001" when (en = '1' and sel = "00") else
"0010" when (en = '1' and sel = "01") else
"0100" when (en = '1' and sel = "10") else
"1000" when (en = '1' and sel = "11") else
"0000";
end architecture dataflow;
architecture dataflow_v2 of decoder2to4 is
signal sel_full : std_logic_vector(2 downto 0);
begin
sel_full <= en & sel; -- concatenate enable with select
with sel_full select
y <= "0001" when "100",
"0010" when "101",
"0100" when "110",
"1000" when "111",
"0000" when others;
end architecture dataflow_v2;
Problem 6
Explain why the following VHDL code contains a potential error and show how to fix it:
architecture bad of example is
signal a, b, c, y : std_logic;
begin
y <= a and b;
y <= b or c;
end architecture bad;
Show Solution
architecture fix1 of example is
signal a, b, c, y : std_logic;
begin
y <= (a and b) or (b or c);
end architecture fix1;
architecture fix2 of example is
signal a, b, c, y, sel : std_logic;
begin
y <= (a and b) when sel = '0' else
(b or c);
end architecture fix2;
architecture fix3 of example is
signal a, b, c : std_logic;
signal y1, y2, y : std_logic;
begin
y1 <= a and b;
y2 <= b or c;
y <= y1 or y2; -- combine as needed
end architecture fix3;
Problem 7
Write a dataflow VHDL description of a 4-bit ripple carry adder using the generate statement. Assume a full_adder component is available.
Show Solution
entity full_adder is
port (
a, b, cin : in std_logic;
sum, cout : out std_logic
);
end entity full_adder;
architecture dataflow of full_adder is
begin
sum <= a xor b xor cin;
cout <= (a and b) or (a and cin) or (b and cin);
end architecture dataflow;
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity ripple_adder4 is
port (
A, B : in std_logic_vector(3 downto 0);
cin : in std_logic;
sum : out std_logic_vector(3 downto 0);
cout : out std_logic
);
end entity ripple_adder4;
architecture structural of ripple_adder4 is
component full_adder is
port (
a, b, cin : in std_logic;
sum, cout : out std_logic
);
end component;
signal carry : std_logic_vector(4 downto 0);
begin
carry(0) <= cin;
gen_adder: for i in 0 to 3 generate
FA: full_adder port map (
a => A(i),
b => B(i),
cin => carry(i),
sum => sum(i),
cout => carry(i+1)
);
end generate gen_adder;
cout <= carry(4);
end architecture structural;
A(0) B(0) A(1) B(1) A(2) B(2) A(3) B(3)
| | | | | | | |
[FA0]------>[FA1]------>[FA2]------>[FA3]----> cout
| ^ | ^ | ^ |
sum(0) cin sum(1) sum(2) sum(3)
Problem 8
Write VHDL concurrent signal assignments to implement the following Boolean equations. Use only basic logic operators (and, or, not, xor).
- \(F_1 = A \cdot B + \overline{C} \cdot D\)
- \(F_2 = (A \oplus B) \cdot (C \oplus D)\)
- \(F_3 = \overline{A \cdot B + C \cdot D}\)
Show Solution
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity bool_equations is
port (
A, B, C, D : in std_logic;
F1, F2, F3 : out std_logic
);
end entity bool_equations;
architecture dataflow of bool_equations is
begin
F1 <= (A and B) or (not C and D);
F2 <= (A xor B) and (C xor D);
F3 <= not ((A and B) or (C and D));
end architecture dataflow;
F1 <= A and B or not C and D; -- ERROR: ambiguous
F1 <= (A and B) or ((not C) and D);
Section C: Process Statements and Behavioral Modeling (4 problems)
Problem 9
Write a VHDL process that implements a 4-to-1 multiplexer using an if-then-else statement. The inputs are d0, d1, d2, d3 (all std_logic), sel is std_logic_vector(1 downto 0), and the output is y.
Show Solution
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity mux4to1 is
port (
d0, d1, d2, d3 : in std_logic;
sel : in std_logic_vector(1 downto 0);
y : out std_logic
);
end entity mux4to1;
architecture behavioral of mux4to1 is
begin
mux_proc: process(d0, d1, d2, d3, sel)
begin
if sel = "00" then
y <= d0;
elsif sel = "01" then
y <= d1;
elsif sel = "10" then
y <= d2;
else
y <= d3;
end if;
end process mux_proc;
end architecture behavioral;
architecture behavioral_v2 of mux4to1 is
begin
mux_proc: process(d0, d1, d2, d3, sel)
begin
case sel is
when "00" => y <= d0;
when "01" => y <= d1;
when "10" => y <= d2;
when "11" => y <= d3;
when others => y <= 'X';
end case;
end process mux_proc;
end architecture behavioral_v2;
Problem 10
What is wrong with the following VHDL process? Explain what hardware it infers and how to fix it.
process(a, b, sel)
begin
if sel = '1' then
y <= a;
end if;
end process;
Show Solution
a ───[D-latch]── y
|
sel ──┘ (enable)
process(a, b, sel)
begin
if sel = '1' then
y <= a;
else
y <= b; -- now y is always assigned
end if;
end process;
process(a, b, sel)
begin
y <= b; -- default assignment
if sel = '1' then
y <= a; -- overrides default when sel='1'
end if;
end process;
Problem 11
Write a VHDL process for a priority encoder with 4 inputs. Input req(3) has highest priority and req(0) has lowest. Output code is a 2-bit encoding of the highest active request, and valid indicates at least one request is active.
Show Solution
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity priority_enc is
port (
req : in std_logic_vector(3 downto 0);
code : out std_logic_vector(1 downto 0);
valid : out std_logic
);
end entity priority_enc;
architecture behavioral of priority_enc is
begin
process(req)
begin
if req(3) = '1' then
code <= "11";
valid <= '1';
elsif req(2) = '1' then
code <= "10";
valid <= '1';
elsif req(1) = '1' then
code <= "01";
valid <= '1';
elsif req(0) = '1' then
code <= "00";
valid <= '1';
else
code <= "00";
valid <= '0';
end if;
end process;
end architecture behavioral;
Problem 12
Explain the role of the sensitivity list in a VHDL process. Show what happens when a signal is accidentally omitted from the sensitivity list.
Show Solution
process(a, b, sel) -- all inputs listed
begin
if sel = '1' then
y <= a;
else
y <= b;
end if;
end process;
process(sel) -- OOPS: a and b missing!
begin
if sel = '1' then
y <= a;
else
y <= b;
end if;
end process;
Time: 0 10 20 30 40 50
sel: 1 1 1 0 0 0
a: 0 1 0 1 0 1
b: 1 0 1 0 1 0
y (correct): 0 1 0 0 1 0
y (buggy sim): 0 0 0 0 0 0
^-- missed! a changed but process didn't wake up
process(all) -- includes a, b, sel automatically
begin
if sel = '1' then
y <= a;
else
y <= b;
end if;
end process;
Section D: Sequential Logic in VHDL (4 problems)
Problem 13
Write a VHDL description of a D flip-flop with synchronous reset and clock enable. Explain how the synthesizer maps this to hardware.
Show Solution
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity dff_sr_ce is
port (
clk : in std_logic;
rst : in std_logic; -- synchronous reset
ce : in std_logic; -- clock enable
d : in std_logic;
q : out std_logic
);
end entity dff_sr_ce;
architecture behavioral of dff_sr_ce is
begin
process(clk)
begin
if rising_edge(clk) then
if rst = '1' then
q <= '0'; -- synchronous reset
elsif ce = '1' then
q <= d; -- load when enabled
end if;
-- when rst='0' and ce='0', q holds (register inferred)
end if;
end process;
end architecture behavioral;
┌──────────────────────────┐
│ Priority MUX │
rst ──────┤ rst=1 → '0' │
ce ───────┤ ce=1 → d ───[D FF]── q
d ────────┤ else → q (hold) │
└──────────────────────────┘
↑
clk ────────────────────────────┘
process(clk, rst) -- rst in sensitivity list
begin
if rst = '1' then -- checked BEFORE clock edge
q <= '0';
elsif rising_edge(clk) then
if ce = '1' then
q <= d;
end if;
end if;
end process;
Problem 14
Write VHDL for a 4-bit binary up counter with synchronous reset and terminal count output. The terminal count tc should be '1' when the counter reaches its maximum value (15).
Show Solution
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity counter4 is
port (
clk : in std_logic;
rst : in std_logic; -- synchronous reset
en : in std_logic; -- count enable
q : out std_logic_vector(3 downto 0);
tc : out std_logic -- terminal count
);
end entity counter4;
architecture behavioral of counter4 is
signal count : unsigned(3 downto 0);
begin
process(clk)
begin
if rising_edge(clk) then
if rst = '1' then
count <= (others => '0');
elsif en = '1' then
count <= count + 1;
end if;
end if;
end process;
q <= std_logic_vector(count);
tc <= '1' when count = 15 else '0';
end architecture behavioral;
clk: _|^|_|^|_|^|_|^|_|^|_|^|_
rst: 1 0 0 0 0 0 0 0 0
en: 0 1 1 1 1 1 1 1 1
q: 0 0 1 2 3 4 ... 14 15 0
tc: 0 0 0 0 0 0 0 1 0
Problem 15
Write VHDL for a Moore finite state machine that detects the sequence "110" on a serial input. Use enumerated types for states and include asynchronous reset.
Show Solution
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity seq_detect_110 is
port (
clk : in std_logic;
rst : in std_logic; -- asynchronous reset
din : in std_logic; -- serial input
det : out std_logic -- detection output
);
end entity seq_detect_110;
architecture behavioral of seq_detect_110 is
type state_type is (S0, S1, S11, S110);
signal current_state, next_state : state_type;
begin
-- State register (sequential process)
state_reg: process(clk, rst)
begin
if rst = '1' then
current_state <= S0;
elsif rising_edge(clk) then
current_state <= next_state;
end if;
end process state_reg;
-- Next-state logic (combinational process)
next_logic: process(current_state, din)
begin
case current_state is
when S0 =>
if din = '1' then
next_state <= S1;
else
next_state <= S0;
end if;
when S1 =>
if din = '1' then
next_state <= S11;
else
next_state <= S0;
end if;
when S11 =>
if din = '0' then
next_state <= S110;
else
next_state <= S11; -- stay (still have "1")
end if;
when S110 =>
if din = '1' then
next_state <= S1; -- overlap: "0" then "1"
else
next_state <= S0;
end if;
end case;
end process next_logic;
-- Output logic (Moore: depends only on state)
det <= '1' when current_state = S110 else '0';
end architecture behavioral;
[S0] --1--> [S1] --1--> [S11] --0--> [S110]
^ <--0-- | <--0-- | | --1--> |
| | | ^ |
| v | (1) |
+------0----+ +--+ 0/1---+
| |
+<---------0---------<-------------+
1 --> S1
Problem 16
Write VHDL for an 8-bit shift register with parallel load, serial input, and bidirectional shift capability. Include a mode select input.
Show Solution
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity shift_reg8 is
port (
clk : in std_logic;
rst : in std_logic;
mode : in std_logic_vector(1 downto 0);
si_left : in std_logic; -- serial input for shift left
si_right: in std_logic; -- serial input for shift right
d_in : in std_logic_vector(7 downto 0); -- parallel load data
q : out std_logic_vector(7 downto 0)
);
end entity shift_reg8;
architecture behavioral of shift_reg8 is
signal reg : std_logic_vector(7 downto 0);
begin
process(clk, rst)
begin
if rst = '1' then
reg <= (others => '0');
elsif rising_edge(clk) then
case mode is
when "00" =>
null; -- hold
when "01" =>
reg <= si_right & reg(7 downto 1); -- shift right
when "10" =>
reg <= reg(6 downto 0) & si_left; -- shift left
when "11" =>
reg <= d_in; -- parallel load
when others =>
null;
end case;
end if;
end process;
q <= reg;
end architecture behavioral;
Before: A B C D E F G H
After: S A B C D E F G (H is shifted out)
Before: A B C D E F G H
After: B C D E F G H S (A is shifted out)
Section E: Testbenches and Synthesis (4 problems)
Problem 17
Write a VHDL testbench for the D flip-flop from Problem 13. Include clock generation, reset stimulus, and verification of synchronous reset behavior.
Show Solution
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity dff_sr_ce_tb is
-- testbench has no ports
end entity dff_sr_ce_tb;
architecture sim of dff_sr_ce_tb is
-- Component declaration
component dff_sr_ce is
port (
clk : in std_logic;
rst : in std_logic;
ce : in std_logic;
d : in std_logic;
q : out std_logic
);
end component;
-- Testbench signals
signal clk_tb : std_logic := '0';
signal rst_tb : std_logic := '0';
signal ce_tb : std_logic := '0';
signal d_tb : std_logic := '0';
signal q_tb : std_logic;
constant CLK_PERIOD : time := 10 ns;
begin
-- Instantiate the Unit Under Test (UUT)
UUT: dff_sr_ce port map (
clk => clk_tb,
rst => rst_tb,
ce => ce_tb,
d => d_tb,
q => q_tb
);
-- Clock generation (non-synthesizable)
clk_proc: process
begin
clk_tb <= '0';
wait for CLK_PERIOD / 2;
clk_tb <= '1';
wait for CLK_PERIOD / 2;
end process clk_proc;
-- Stimulus process
stim_proc: process
begin
-- Initialize
rst_tb <= '1'; ce_tb <= '0'; d_tb <= '0';
wait for 2 * CLK_PERIOD;
-- Release reset
rst_tb <= '0';
wait for CLK_PERIOD;
-- Test 1: CE=0, data should not load
ce_tb <= '0'; d_tb <= '1';
wait for CLK_PERIOD;
assert q_tb = '0'
report "FAIL: Q should remain 0 when CE=0"
severity error;
-- Test 2: CE=1, data should load
ce_tb <= '1'; d_tb <= '1';
wait for CLK_PERIOD;
assert q_tb = '1'
report "FAIL: Q should be 1 after loading d=1"
severity error;
-- Test 3: CE=1, load 0
d_tb <= '0';
wait for CLK_PERIOD;
assert q_tb = '0'
report "FAIL: Q should be 0 after loading d=0"
severity error;
-- Test 4: Synchronous reset while CE=1
d_tb <= '1';
wait for CLK_PERIOD; -- q should become 1
rst_tb <= '1';
wait for CLK_PERIOD; -- sync reset clears q
assert q_tb = '0'
report "FAIL: Q should be 0 after synchronous reset"
severity error;
-- Test complete
rst_tb <= '0'; ce_tb <= '0';
report "All tests passed!" severity note;
wait; -- stop simulation
end process stim_proc;
end architecture sim;
┌─────────────────────────────┐
│ Testbench │
│ │
│ clk_proc ──> clk_tb ──┐ │
│ │ │
│ stim_proc ─> rst_tb ──┼──[UUT]──> q_tb
│ > ce_tb ──┤ │
│ > d_tb ──┘ │
│ │
│ assert statements │
└─────────────────────────────┘
Problem 18
Identify whether each of the following VHDL constructs is synthesizable or non-synthesizable, and explain why.
wait for 10 ns;rising_edge(clk)assert (count < 10) report "overflow" severity error;for i in 0 to 7 loopwhile count > 0 loopafter 5 ns
Show Solution
Problem 19
The following VHDL code is intended to describe a combinational circuit, but it infers latches. Identify all the latches and rewrite the code to be purely combinational.
process(a, b, c, sel)
begin
case sel is
when "00" =>
x <= a;
y <= b;
when "01" =>
x <= b;
when "10" =>
y <= c;
when others =>
x <= '0';
y <= '0';
end case;
end process;
Show Solution
process(a, b, c, sel)
begin
-- Default assignments prevent latches
x <= '0';
y <= '0';
case sel is
when "00" =>
x <= a;
y <= b;
when "01" =>
x <= b;
-- y keeps default '0'
when "10" =>
y <= c;
-- x keeps default '0'
when others =>
x <= '0';
y <= '0';
end case;
end process;
process(a, b, c, sel)
begin
case sel is
when "00" =>
x <= a;
y <= b;
when "01" =>
x <= b;
y <= '0'; -- added
when "10" =>
x <= '0'; -- added
y <= c;
when others =>
x <= '0';
y <= '0';
end case;
end process;
process(all) -- VHDL-2008: all signals in sensitivity list
begin
-- Defaults
x <= '0';
y <= '0';
z <= '0';
-- Only override what changes
case sel is
when "00" => x <= a;
when "01" => y <= b;
when others => null;
end case;
end process;
Problem 20
A designer writes the following VHDL for what they intend to be a flip-flop with enable. Explain what actually gets synthesized and write the corrected version.
process(clk, en, d)
begin
if en = '1' then
if rising_edge(clk) then
q <= d;
end if;
end if;
end process;
Show Solution
en ──[AND]──> gated_clk ──> [D FF] ──> q
clk ─┘ d ──┘
process(clk)
begin
if rising_edge(clk) then
if en = '1' then
q <= d;
end if;
end if;
end process;
┌──────────┐
en ───────┤ 2:1 MUX ├──D──[D FF]── q
d ────────┤ │ ↑
q(feedback)┤ │ │
└──────────┘ clk─┘
process(clk, async_rst) -- only clk (and async_rst if used)
begin
if async_rst = '1' then -- optional async reset (outermost)
q <= '0';
elsif rising_edge(clk) then -- clock edge
if sync_rst = '1' then -- sync reset inside clock
q <= '0';
elsif en = '1' then -- enable inside clock
q <= d;
end if;
end if;
end process;
Problems Summary
| Section | Topics Covered | Problem Count |
|---|---|---|
| A | Entity and Architecture | 4 |
| B | Concurrent Statements and Dataflow | 4 |
| C | Process Statements and Behavioral Modeling | 4 |
| D | Sequential Logic in VHDL | 4 |
| E | Testbenches and Synthesis | 4 |
| Total | 20 |