Programming lesson
Designing a Programmable BCD Counter for FPGA: Lab 3 Tutorial (2025)
Learn how to design a programmable counter with BCD output for FPGA synthesis. Step-by-step Verilog guide for CDA4203L Lab 3, including top-level integration, simulation, and board demonstration.
Introduction to Programmable Counters and BCD Conversion
In this tutorial, we explore the design of a programmable counter that outputs binary-coded decimal (BCD) values and is synthesized on an FPGA board. This lab is part of the CDA4203L Spring 2025 Computer System Design Lab, focusing on advanced sequential hardware design using Verilog. The counter counts from 0 to a user-defined maximum (0–99) and outputs two BCD digits. We'll cover the top-level block diagram, Verilog modules, testbench creation, and FPGA implementation using the Anvyl board.
Understanding the System Architecture
The system consists of a 7-bit binary counter, a programmable wrapper that stops counting at a user-set maximum, and a binary-to-BCD converter. The top module, final_bcd_counter, instantiates these components. Inputs include max_count (7 bits), run (1 bit), and a clock. Outputs are digit_1 (ones) and digit_2 (tens), each 4-bit BCD.
Key Modules Provided
- Counter.v: A 7-bit binary counter with enable and synchronous reset.
- Binary_bcd.v: Converts 7-bit binary to two BCD digits using the double-dabble algorithm.
- Prog_counter.v (to complete): Adds programmability to stop at
max_count. - Final_bcd_counter.v (to complete): Top module instantiating the above.
- Lab_board.v: Provides I/O mapping for the Anvyl board.
Step-by-Step Design Process
1. Complete the Programmable Counter (Prog_counter.v)
This module wraps the 7-bit counter and adds logic to stop when the count equals max_count. When run is 0, the counter resets to 0 and allows setting max_count. When run is 1, the counter increments on each clock cycle until it reaches max_count, then stops.
module prog_counter(
input clk,
input rst,
input run,
input [6:0] max_count,
output reg [6:0] count_out
);
wire enable;
assign enable = run && (count_out < max_count);
always @(posedge clk or posedge rst) begin
if (rst) count_out <= 7'd0;
else if (!run) count_out <= 7'd0;
else if (enable) count_out <= count_out + 1;
end
endmodule2. Complete the Top Module (Final_bcd_counter.v)
Instantiate the programmable counter and the binary-to-BCD converter. Connect the counter output to the converter input, and map the BCD outputs to digit_1 and digit_2.
module final_bcd_counter(
input clk,
input rst,
input run,
input [6:0] max_count,
output [3:0] digit_1,
output [3:0] digit_2
);
wire [6:0] count_binary;
prog_counter u_counter(
.clk(clk),
.rst(rst),
.run(run),
.max_count(max_count),
.count_out(count_binary)
);
binary_bcd u_converter(
.binary_in(count_binary),
.bcd_ones(digit_1),
.bcd_tens(digit_2)
);
endmodule3. Write a Testbench for Exhaustive Testing
Create a testbench that tests all valid max_count values (0–99) and both run states. Use a loop to simulate setting each maximum, then running the counter. Verify that the counter stops at the correct value and that BCD outputs are correct.
module tb_final_bcd_counter;
reg clk, rst, run;
reg [6:0] max_count;
wire [3:0] digit_1, digit_2;
final_bcd_counter uut(...);
always #5 clk = ~clk;
initial begin
clk = 0; rst = 1; run = 0; max_count = 7'd99;
#20 rst = 0;
// Test max_count = 50
max_count = 7'd50;
#20 run = 1;
#2000 run = 0;
// Test max_count = 99
max_count = 7'd99;
#20 run = 1;
#4000 $finish;
end
endmoduleFPGA Synthesis and Board Demonstration
After simulation, synthesize the design using Xilinx ISE or Vivado. Use the provided UCF file to map ports: run to SW7, max_count[6:0] to SW6–SW0, digit_1 to LED3–LED0, digit_2 to LED7–LED4. Generate the bitstream and program the Anvyl board. Record a video showing the counter running for different max_count values, demonstrating that it stops correctly and displays BCD on the LEDs.
Common Pitfalls and Debugging Tips
Ensure that the counter resets properly when run is low. Check that the binary-to-BCD converter works for all values 0–99. Use simulation to verify that the counter stops exactly at max_count and does not overflow. Also, confirm that the clock is divided appropriately if the 100 MHz clock is used directly; you may need a clock divider to make the count visible on LEDs.
Real-World Application: Counting in Sports and Gaming
Programmable counters are used in many real-world systems, such as scoreboards in sports events or progress bars in video games. For example, a basketball shot clock counts down from 24 to 0; a programmable counter could set the initial time. Similarly, in gaming, a health bar that decreases from a maximum value uses similar logic. This lab teaches the fundamentals of such systems.
Conclusion
By completing this lab, you gain hands-on experience with sequential design, BCD conversion, and FPGA synthesis. These skills are essential for digital system design and are widely used in industry for embedded systems, IoT devices, and consumer electronics. Submit your Verilog files, testbench, simulation waveforms, UCF file, and video link as per the lab instructions.