Project 2: 4-to-1 Multiplexer
Build a 4-to-1 mux with select lines and a complete testbench.
Quick Reference
| Attribute | Value |
|---|---|
| Difficulty | Beginner |
| Time Estimate | 2-3 hours |
| Main Programming Language | Verilog (Alternatives: VHDL, SystemVerilog) |
| Alternative Programming Languages | VHDL, SystemVerilog |
| Coolness Level | Low |
| Business Potential | Low |
| Prerequisites | Combinational logic, Case statements, Truth tables |
| Key Topics | MUX design, Case logic, Latch avoidance |
1. Learning Objectives
- Implement combinational selection logic
- Avoid latch inference in always blocks
- Write a testbench that explores select combinations
2. All Theory Needed (Per-Concept Breakdown)
Combinational Logic Modeling
Description/Expanded Explanation of the concept
Combinational logic produces outputs that depend only on current inputs. In Verilog, this is modeled using assign or always @(*) blocks. The key rule is that every output must be assigned for every input condition, otherwise you create unintended storage (latches).
Definitions & Key Terms
- Combinational logic -> outputs depend only on current inputs
- Continuous assignment ->
assignfor wire-driven logic - Latch -> unintended storage inferred by incomplete assignments
Mental Model Diagram (ASCII)
inputs --> [logic] --> outputs

How It Works (Step-by-Step)
- Choose
assignfor simple logic oralways @(*)for complex logic. - Ensure outputs are assigned in all branches.
- Verify with exhaustive or directed tests.
Minimal Concrete Example
always @(*) begin
if (sel) y = b; else y = a;
end
Common Misconceptions
- “Missing default just means don’t care.” -> It creates a latch.
- “Blocking assignments are always wrong.” -> They are correct in combinational blocks.
Check-Your-Understanding Questions
- What hardware does an if/else create?
- Why does a missing default create storage?
- When should you use
assignvsalways @(*)?
Where You’ll Apply It
- This project: used in Section 3.2 and Section 5.3
- Also used in: P01-digital-gate-library.md, P03-7-segment-display-decoder.md, P04-4-bit-ripple-carry-adder.md
Boolean Algebra and Truth Tables
Description/Expanded Explanation of the concept
Boolean algebra is the math of digital logic. A truth table is the exact, exhaustive mapping from inputs to outputs. In hardware, there is no “default” or “implicit” behavior: every input combination must map to a defined output. This is the foundation of reliable combinational circuits.
Definitions & Key Terms
- Boolean algebra -> algebra of 0/1 variables with AND/OR/NOT operators
- Truth table -> exhaustive input/output mapping
- Minterm -> AND of variables producing 1 for one input combination
- Maxterm -> OR of variables producing 0 for one input combination
Mental Model Diagram (ASCII)
Inputs -> [Truth Table] -> Boolean Expression -> Gates

How It Works (Step-by-Step)
- List all input combinations.
- Mark which combinations should produce 1.
- Translate the table into an expression or directly into gates.
- Verify with exhaustive simulation.
Minimal Concrete Example
// AND gate truth table: y = a & b
assign y = a & b;
Common Misconceptions
- “If it works for some cases, it’s fine.” -> All cases must be correct.
- “Truth tables are only for beginners.” -> They remain the most reliable spec.
Check-Your-Understanding Questions
- What output should an XOR produce for inputs 01 and 10?
- How many rows does a truth table have for 4 inputs?
- Explain why a missing row is a bug in hardware.
Where You’ll Apply It
- This project: used in Section 3.2 (functional requirements) and Section 6 (testing)
- Also used in: P02-4-to-1-multiplexer.md, P03-7-segment-display-decoder.md
Verification with Testbenches and Waveforms
Description/Expanded Explanation of the concept
Testbenches are simulation-only modules that apply stimulus and check outputs. Waveforms (VCD) are the hardware engineer’s microscope; they reveal timing, glitches, and ordering problems. A good testbench is deterministic and covers edge cases.
Definitions & Key Terms
- Testbench -> a non-synthesizable module that drives a DUT
- VCD -> Value Change Dump waveform file
- Deterministic test -> same inputs produce same outputs every run
Mental Model Diagram (ASCII)
[Testbench] -> [DUT] -> [VCD] -> [GTKWave]

How It Works (Step-by-Step)
- Initialize inputs to known values.
- Apply stimulus over time.
- Dump waveforms and check outputs.
- Add assertions or PASS/FAIL messages.
Minimal Concrete Example
initial begin
$dumpfile("wave.vcd");
$dumpvars(0, tb);
a = 0; b = 1; #10;
$finish;
end
Common Misconceptions
- “If it simulates once, it’s correct.” -> Cover all relevant cases.
- “Waveforms are optional.” -> They are often the only way to debug timing.
Check-Your-Understanding Questions
- Why keep testbench and DUT separate?
- What is the purpose of
$dumpvars? - How do you make a testbench deterministic?
Where You’ll Apply It
- This project: used throughout Section 6 (testing)
- Also used in: all other projects in this folder
3. Project Specification
3.1 What You Will Build
A 4-to-1 multiplexer with select input and testbench verifying all select values.
3.2 Functional Requirements
- Requirement 1: Select one of four inputs based on a 2-bit select
- Requirement 2: Define behavior for invalid select (default)
- Requirement 3: Produce waveforms that show clean routing
3.3 Non-Functional Requirements
- Performance: Stable operation at the target clock and interfaces.
- Reliability: Deterministic outputs on all defined inputs.
- Usability: Clear ports and documented behavior.
3.4 Example Usage / Output
{p['example_usage']}
3.5 Data Formats / Schemas / Protocols
{p[‘data_format’]}
3.6 Edge Cases
- Select X/Z
- Default path coverage
3.7 Real World Outcome
3.7.1 How to Run (Copy/Paste)
vvp mux_tb
3.7.2 Golden Path Demo (Deterministic)
Run the demo command above with the provided testbench and confirm the outputs match the golden transcript.
3.7.3 CLI Transcript
sel=00 -> y=a
sel=01 -> y=b
sel=10 -> y=c
sel=11 -> y=d
3.7.4 Failure Demo (Expected)
# Example failure case
ERROR: Output mismatch at vector 3
Expected: 0x0A, Got: 0x0B
EXIT CODE: 1
Notes:
- Exit code 0 indicates all tests passed
- Exit code 1 indicates a test failure
4. Solution Architecture
4.1 High-Level Design
[inputs] -> [core logic] -> [outputs]

4.2 Key Components
| Component | Responsibility |
|---|---|
| mux4 | Combinational mux logic |
| mux_tb | Testbench with select sweep |
4.3 Data Structures (No Full Code)
// Example signals (adapt to your design)
reg [7:0] state_reg;
reg [7:0] data_reg;
4.4 Algorithm Overview
Key Algorithm: Core control flow
- Initialize state/reset conditions.
- Apply inputs and compute outputs.
- Update state on clock edges (if sequential).
Complexity Analysis:
- Time: O(1) per cycle
- Space: O(N) for registers and logic
5. Implementation Guide
5.1 Development Environment Setup
iverilog -v
# Ensure GTKWave is installed for waveform viewing
5.2 Project Structure
project-root/
|-- src/
| |-- top.v
| |-- core.v
|-- tb/
| |-- tb.v
|-- Makefile
|-- README.md

5.3 The Core Question You’re Answering
“How does hardware choose one signal from many?”
5.4 Concepts You Must Understand First
- Combinational logic
- Case statements
- Truth tables
5.5 Questions to Guide Your Design
- What should happen if sel is X?
- Should the output default to a known safe value?
5.6 Thinking Exercise
Draw a 4-to-1 mux using AND/OR gates and label select inversions.
5.7 The Interview Questions They’ll Ask
- What hardware does an if/else create?
- Why is a default case required?
- What is a priority mux?
5.8 Hints in Layers
- Use a case statement with all 4 select values.
- Assign output in every branch.
- Add a default assignment for safety.
5.9 Books That Will Help
| Topic | Book | Chapter |
|---|---|---|
| Combinational logic | Digital Design and Computer Architecture | Ch. 2 |
| Verilog case statements | Digital Design and Computer Architecture | Ch. 4 |
5.10 Implementation Phases
Phase 1: Foundation
Goals:
- Establish core module structure
- Implement minimal behavior
Tasks:
- Scaffold module ports and internal signals
- Write a minimal testbench that compiles
Checkpoint: Simulation runs without errors
Phase 2: Core Functionality
Goals:
- Implement full logic
- Verify edge cases
Tasks:
- Complete core logic
- Add directed tests for edge cases
Checkpoint: All tests pass and waveforms match expectations
Phase 3: Polish & Edge Cases
Goals:
- Improve readability
- Document behavior
Tasks:
- Add comments and README notes
- Expand tests for unusual inputs
Checkpoint: Design is deterministic and documented
5.11 Key Implementation Decisions
| Decision | Options | Recommendation | Rationale |
|---|---|---|---|
| Reset strategy | Sync / Async | Sync | Simpler timing closure |
| Test coverage | Directed / Exhaustive | Exhaustive for small logic | Prevents missed cases |
6. Testing Strategy
6.1 Test Categories
| Category | Purpose | Examples |
|---|---|---|
| Unit Tests | Test core logic | Small vectors |
| Integration Tests | Test modules together | Full system |
| Edge Case Tests | Boundary conditions | Max/min values |
6.2 Critical Test Cases
- Test 1: Verify output for all 4 select values
- Test 2: Toggle select mid-cycle and confirm output updates
- Test 3: Check for latches in synthesis warnings
6.3 Test Data
Use deterministic vectors and document expected outputs.
7. Common Pitfalls & Debugging
7.1 Frequent Mistakes
| Pitfall | Symptom | Solution |
|---|---|---|
| Latch inference | Output holds old value | Assign output in every branch |
7.2 Debugging Strategies
- Inspect waveforms at key internal signals
- Add temporary debug outputs to verify state
- Reduce testcases to the smallest failing case
7.3 Performance Traps
- Overly wide counters or combinational paths can reduce max clock
8. Extensions & Challenges
8.1 Beginner Extensions
- Add parameterization for widths
- Add optional features (enable, reset)
8.2 Intermediate Extensions
- Add configuration registers
- Build a simple driver or demo program
8.3 Advanced Extensions
- Integrate with another project in this series
- Implement a hardware demo on FPGA
9. Real-World Connections
9.1 Industry Applications
- Digital control systems and embedded peripherals
- FPGA prototyping and validation
9.2 Related Open Source Projects
- Yosys / nextpnr toolchain for open-source FPGA flow
- Example HDL projects in the FPGA community
9.3 Interview Relevance
- Demonstrates RTL thinking and verification skills
10. Resources
10.1 Essential Reading
- Digital Design and Computer Architecture - Focus on Ch. 2
- Digital Design and Computer Architecture - Focus on Ch. 4
10.2 Video Resources
- Search for project-specific HDL walkthroughs and waveforms
10.3 Tools & Documentation
- Icarus Verilog
- GTKWave
10.4 Related Projects in This Series
- See adjacent projects in
VERILOG_FROM_ZERO_PROJECTS/
11. Self-Assessment Checklist
11.1 Understanding
- I can explain the core concept without notes
- I can predict waveform behavior for basic inputs
11.2 Implementation
- All functional requirements are met
- All tests pass
- Edge cases are documented
11.3 Growth
- I can explain this project in an interview
- I documented at least one lesson learned
12. Submission / Completion Criteria
Minimum Viable Completion:
- Functional requirements implemented
- Testbench passes
- Waveforms inspected
Full Completion:
- All minimum criteria plus
- Edge cases covered and documented
Excellence (Going Above & Beyond):
- Hardware demo on FPGA
- Clear write-up of lessons learned
Appendix A: Deep Dive Walkthrough
A.1 Signal Map and Invariants
- Inputs:
d0,d1,d2,d3,sel[1:0] - Output:
y
Invariant: y == d{sel} for all sel values.
A.2 Truth Table (Binary Select)
| sel | y | |—–|—-| | 00 | d0 | | 01 | d1 | | 10 | d2 | | 11 | d3 |
A.3 Timing Sketch
Time: t0 t1 t2 t3
sel: 00 01 10 11
y: d0 d1 d2 d3

A.4 Implementation Options and Trade-offs
- Case statement: clear and synthesizes to a mux.
- Ternary chain: compact but can be harder to read.
- One-hot select: easier to debug but uses more logic.
A.5 Testbench Vector Set (Deterministic)
- Set all inputs to unique values:
d0=8'hA0,d1=8'hB1,d2=8'hC2,d3=8'hD3. - Sweep
selfrom 0 to 3 and verify output equals the selected input.
A.6 Waveform Debug Tips
- If
yglitches, confirmselchanges are not overlapping with input toggles. - If
yshows X, ensure all inputs are initialized.
13. Deep Dive Appendix
13.1 Timing and Resource Budget
- A 4-to-1 mux is typically two LUT levels (two 2-to-1 muxes feeding a final mux).
- Glitches can appear if select changes while inputs toggle. In purely combinational logic, this is normal.
- For FPGA targets, the mux maps efficiently into LUTs; the critical path is usually the select decoding.
13.2 Waveform Interpretation Guide
- Verify that y tracks d0..d3 based on
selwith no clock required. - If using a
case, ensure there is a default so y is always driven.
Minimal trace:
sel=00 -> y=d0
sel=01 -> y=d1
sel=10 -> y=d2
sel=11 -> y=d3
13.3 Hardware Bring-Up Notes
- Connect d0..d3 to four switches, sel[1:0] to two switches.
- Connect y to one LED. Flip switches to see output routing.
- Use pin constraints to avoid floating inputs (add pull-ups if needed).
13.4 Alternate Implementations and Trade-offs
- Tree of 2-to-1 muxes: clearer hierarchy, matches real silicon.
- Case statement: clearer RTL, synthesizes efficiently.
- Boolean expression: compact but harder to read.
13.5 Additional Exercises
- Build an 8-to-1 mux from 2-to-1 muxes and compare depth.
- Add an enable input that forces y=0 when disabled.
- Make the mux parameterizable for data width and number of inputs.