Video 4 of 4 · ~8 minutes · Topic 8 Capstone
Dr. Mike Borowczak · Electrical & Computer Engineering · CECS · UCF
The libraries you use every day in software — libc, OpenSSL, zlib, libpng, SQLite — were written in the 1990s and still run inside everything. Their hardware equivalents — UART controllers, SPI masters, AXI bridges, DDR controllers — predate that and still ship in this year's silicon. When a building block is done well, you forget it exists. When it's done badly, every team rewrites their own version, and the same bug appears in twenty places at once.
Heartbleed was one flaw in one widely-shared library that suddenly meant every web server on Earth was exposed simultaneously. The opposite failure — when teams don't share — is worse over the long run: ten teams writing ten almost-identical blocks, each with their own bugs, none documented well enough for the next engineer to safely pick up. Both are reuse failures. Both show up in bug trackers for years.
| Module | Topic | Parameters | Where it lives |
|---|---|---|---|
debounce | 5 | CLKS_STABLE | shared/lib/ — reference impl |
edge_detect | 5 | — | shared/lib/ — reference impl |
counter_mod_n | 5 | N | shared/lib/ — reference impl |
sync_2ff | 5 | WIDTH | lecture example (d08_s1_ex1) |
traffic_light | 7 | — | lab (week2_day07/ex1) |
pattern_detector | 7 | — | lab (week2_day07/ex2) |
button_array | 8 | N, CLKS_STABLE | lecture example (d08_s3_ex3) |
piso_shift / sipo_shift | 5* | WIDTH | not yet built — you’ll need these |
fifo | 8* | DEPTH, WIDTH | sketched today — not yet built |
shared/lib/ ready to instantiate; others exist as starter/solution code in your labs; a few you haven’t built yet. The next theme’s composition work (UART = shift + baud + FSM; SPI = shift + debounce) will surface the gaps — that’s when we promote the lab versions into the shared library.
Hard-coded widths. Assumes particular clock rate. Testbench works only with “my” input pattern. Undocumented. Signal names reflect current project, not purpose. Sub-modules tangled with the top. Only original author can use it — and only in this project.
Parameterized over everything that varies. Clock-rate independence where possible. Testbench covers the module's contract (not a specific application). Documented inputs, outputs, behavior, timing, assumptions. Named for function. Self-contained — no external dependencies. A stranger can drop it in and it works.
//----------------------------------------------------
// debounce.v — counter-based switch debouncer
//
// Takes an asynchronous, bouncing input, produces
// a clean version that only changes after
// CLKS_STABLE consecutive cycles of persistence.
//
// Parameters:
// CLKS_STABLE : cycles before accepting new value
// (default 500_000 = 20ms @ 25MHz)
//
// Ports:
// i_clk : synchronous clock
// i_reset : synchronous reset (active high)
// i_noisy : input from external switch
// o_clean : stable debounced output
//
// Latency: up to CLKS_STABLE cycles.
// Usage: debounce #(.CLKS_STABLE(N)) u_deb (...);
//----------------------------------------------------
module debounce #(parameter CLKS_STABLE=500_000) (
input wire i_clk, i_reset, i_noisy,
output reg o_clean
);
// ... implementation ...
endmodule
make stat produces expected cell countPick a module from any earlier lab. Score it against the reusability checklist. For each unchecked box, name the work you’d do to check it.
25_000_000 or 250_000 → parameterize CLKS_PER_SECtmp, x, cnt → rename for purposemake simBEFORE: “works for me”
module btn (
input clk, rst, x,
output y
);
reg [18:0] cnt;
// ... 20 ms @ 25 MHz ...
// (hard-coded)
endmodule
AFTER: reusable
// Header comment: datasheet
module debounce #(
parameter CLKS_STABLE = 500_000
) (
input wire i_clk, i_reset, i_noisy,
output reg o_clean
);
localparam W = $clog2(CLKS_STABLE);
reg [W-1:0] r_count;
// ... logic with docs ...
endmodule
Ask AI: “Here's my debouncer. Refactor it to be reusable: add a parameter for the debounce window, auto-size the counter width, add a header comment block in a datasheet style, and rename signals with the i_/o_/r_ convention.”
TASK
AI refactors to reusable style.
BEFORE
Predict: parameter added, $clog2 used, renamed signals, datasheet comment.
AFTER
Strong AI documents latency + timing assumptions. Weak AI only does syntactic rename.
TAKEAWAY
“Reusable” means semantic changes + docs, not just renaming.
① A module is reusable when a stranger can use it from the header alone.
② Everything that could vary is a parameter; everything else is documented.
③ The header comment is the IP datasheet. Write it as such.
④ Your module library becomes the next theme’s UART + SPI backbone.
Q1: Name three things that should be parameterized in a debouncer module.
Q2: What goes in a header comment block that doesn't go in the Verilog code itself?
Q3: Why is signal naming part of reusability?
sw1_press, fan_on) can't be used in other projects. Signals with functional names (i_noisy, o_clean) work everywhere.Q4: What single question do you ask to tell if a testbench tests a module's contract vs. a specific application?
🔗 End of Topic 8 · Hierarchy & Reuse
UART · SPI · Integration Projects
▸ WHY THIS MATTERS NEXT
You’ve now learned the alphabet of hardware design: combinational logic, sequential logic, synchronization, verification, state machines, and reuse. The next theme is where you compose words and sentences. UART TX + RX — to actually talk to your computer over a serial cable. SPI master — to drive peripherals. Your module library from the foundational topics isn’t the byproduct; it’s the material of the upcoming designs. You’re not going to learn many new primitives next — you’re going to build real things out of the ones you already have. See you in the next topic.