Project 18: VGA Pattern Generator
Generate 640x480@60Hz VGA timing and draw color bars.
Quick Reference
| Attribute | Value |
|---|---|
| Difficulty | Advanced |
| Time Estimate | 1-2 weeks |
| Main Programming Language | Verilog (Alternatives: VHDL, SystemVerilog) |
| Alternative Programming Languages | VHDL, SystemVerilog |
| Coolness Level | High |
| Business Potential | Low |
| Prerequisites | Counters, Timing |
| Key Topics | VGA sync, Pixel counters |
1. Learning Objectives
- Generate HSYNC and VSYNC correctly
- Identify visible region
- Render static patterns
2. All Theory Needed (Per-Concept Breakdown)
VGA Timing and Scan Counters
Description/Expanded Explanation of the concept
VGA displays pixels by scanning rows and columns at precise timing. Horizontal and vertical counters generate sync pulses and identify the visible region. If timing is wrong, the image rolls or flickers.
Definitions & Key Terms
- Front porch / back porch -> blanking intervals around visible area
- HSYNC/VSYNC -> sync pulses for horizontal and vertical timing
- Pixel clock -> rate of pixel output
Mental Model Diagram (ASCII)
[visible] [front] [sync] [back] -> repeat

How It Works (Step-by-Step)
- Increment horizontal counter each pixel.
- When end-of-line reached, reset hcount and increment vcount.
- Generate HSYNC/VSYNC based on counter ranges.
- Output pixels only in visible region.
Minimal Concrete Example
visible = (hcount < 640) && (vcount < 480);
Common Misconceptions
- “Any pixel clock works.” -> VGA requires exact timing.
- “You can skip blanking.” -> Sync pulses must be correct.
Check-Your-Understanding Questions
- Why are porches required?
- What happens if HSYNC width is wrong?
- How do you compute total line length?
Where You’ll Apply It
- This project: used in Section 3.2 and Section 4
- Also used in: P20-pong-game-on-vga.md
Counters and Clock Enables
Description/Expanded Explanation of the concept
Counters are registers that increment or decrement each clock cycle. Clock enables allow you to update a register only when needed, which is safer than gating clocks. They are essential for timing, PWM, and pacing visible outputs.
Definitions & Key Terms
- Counter -> register that increments/decrements
- Clock enable -> condition that allows a register update
- Prescaler -> counter used to slow down a signal
Mental Model Diagram (ASCII)
clk -> [counter] --tick--> [slow logic]

How It Works (Step-by-Step)
- Increment counter each clock edge.
- When counter reaches a limit, assert a tick.
- Use tick as a clock enable for slower logic.
Minimal Concrete Example
if (tick) out <= out + 1;
Common Misconceptions
- “Gating the clock is simpler.” -> It can break timing and glitch.
- “Counters are always free.” -> Wide counters consume resources.
Check-Your-Understanding Questions
- Why use clock enables instead of gating clocks?
- How do you choose counter width for a target frequency?
- What happens when a counter overflows?
Where You’ll Apply It
- This project: used in Section 3.2 and Section 5
- Also used in: P08-shift-register-led-chaser.md, P10-pwm-generator-led-dimmer-servo-control.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 VGA controller that outputs color bars at 640x480@60Hz.
3.2 Functional Requirements
- Requirement 1: Generate correct sync pulses
- Requirement 2: Drive RGB only in visible region
- Requirement 3: Use correct pixel clock
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
- Wrong porch values
- Sync polarity
3.7 Real World Outcome
3.7.1 How to Run (Copy/Paste)
vvp vga_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
HSYNC=31.77 kHz VSYNC=60 Hz
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 |
|---|---|
| hcount | Horizontal counter |
| vcount | Vertical counter |
| sync_gen | Sync pulse generator |
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 do you generate precise timing for video output?”
5.4 Concepts You Must Understand First
- Counters
- Timing
5.5 Questions to Guide Your Design
- What is the pixel clock?
- What porch values are required?
5.6 Thinking Exercise
Compute total pixels per line and per frame.
5.7 The Interview Questions They’ll Ask
- Why do porches exist?
- How does sync polarity matter?
5.8 Hints in Layers
- Use counters for horizontal and vertical positions.
- Gate RGB output to visible region.
5.9 Books That Will Help
| Topic | Book | Chapter |
|---|---|---|
| Graphics basics | Computer Graphics from Scratch | Ch. 1 |
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 hcount and vcount reset
- Test 2: Check visible gating logic
6.3 Test Data
Use deterministic vectors and document expected outputs.
7. Common Pitfalls & Debugging
7.1 Frequent Mistakes
| Pitfall | Symptom | Solution |
|---|---|---|
| Rolling image | Sync timing wrong | Verify porch/sync counts |
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
- Computer Graphics from Scratch - Focus on Ch. 1
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 Timing Constants
- Outputs:
hsync,vsync,rgb[2:0](or wider) - Counters:
hcount[9:0],vcount[9:0]
640x480@60 timing:
- H: visible 640, front porch 16, sync 96, back porch 48 -> total 800
- V: visible 480, front porch 10, sync 2, back porch 33 -> total 525
- Pixel clock: 25.175 MHz (25 MHz is acceptable for FPGA demos)
A.2 Visible Region Logic
visible = (hcount < 640) && (vcount < 480)
A.3 Deterministic Test Plan
- Verify
hsynclow for 96 cycles each line. - Verify
vsynclow for 2 lines each frame. - Capture a frame and confirm 8 vertical bars.
A.4 Debugging Tip
If the image rolls, your total counts are wrong. If it shifts, your porch values are wrong.
13. Deep Dive Appendix
13.1 Timing and Resource Budget
- 640x480@60 requires 25.175 MHz pixel clock and 800x525 total timing.
- HSYNC and VSYNC pulses must be exact or monitors may lose lock.
- The pixel pipeline is often the critical path; keep color math simple.
13.2 Waveform Interpretation Guide
- Verify hcount runs 0..799 and vcount runs 0..524.
- HSYNC should be low during the sync window; VSYNC low during vertical sync.
- visible should be high only when hcount<640 and vcount<480.
Example timing summary:
h: 640 visible + 16 front + 96 sync + 48 back = 800
v: 480 visible + 10 front + 2 sync + 33 back = 525
13.3 Hardware Bring-Up Notes
- Build a resistor DAC (e.g., 3 bits per color) for VGA analog levels.
- Use correct VGA pinout; double-check HSYNC/VSYNC polarity.
- If image rolls, check sync timing and pixel clock.
13.4 Alternate Implementations and Trade-offs
- Downscale to 320x240 and double pixels for easier timing.
- Add a framebuffer in RAM for arbitrary images.
- Use color bars vs checkerboard to verify timing and color order.
13.5 Additional Exercises
- Draw a checkerboard and verify pixel alignment.
- Add a moving sprite with a simple position register.
- Implement text overlay using a small font ROM.