Skip to content

Final project - Counter module

Code

`timescale 1ns/1ps

module counter #(parameter THRESHOLD = 16'b1111111111111111)(
    input  wire       clk,       // Clock
    input  wire       rst_n,     // Reset (active low)
    input  wire       data_in,   // data to count
    output reg[15:0]  data_cnt,  // count
    output wire       finish     // high when the counter reaches the threshold
);

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin 
            data_cnt <= 0;
        end
        else if (data_in && data_cnt < THRESHOLD) begin
           data_cnt <= data_cnt + 1;
        end 
    end

    assign finish = (data_cnt == THRESHOLD);

endmodule

Lint

verilator --lint-only -Wall -Ilib puf/counter.v
- V e r i l a t i o n   R e p o r t: Verilator 5.044 2026-01-01 rev v5.044
- Verilator: Built from 0.031 MB sources in 2 modules, into 0.012 MB in 3 C++ files needing 0.000 MB
- Verilator: Walltime 0.005 s (elab=0.000, cvt=0.002, bld=0.000); cpu 0.005 s on 1 threads; alloced 30.344 MB

Test harness

`timescale 1ns/1ps

module test_counter;
    // Inputs are reg (we drive them)
    reg clk, rst_n, data_in;

    // Outputs are wire (DUT drives them)
    wire[15:0] data_cnt;
    wire finish;

    // Instantiate Device Under Test with a threshold value of 2
    counter #(.THRESHOLD(2'b10)) myCounter (
        .clk(clk),
        .rst_n(rst_n),
        .data_in(data_in),      
        .data_cnt(data_cnt),
        .finish(finish)
    );

    // Clock generation
    always #10 clk = ~clk;  // 50 MHz (20ns period)

    // Test stimulus
    initial begin
        $dumpfile("waves.vcd");
        $dumpvars(0, test_counter);

        // Initialize
        $display("Initialize");
        #10 
        clk = 0;        
        display;

        // Reset
        $display("----------- Reset --------------");
        rst_n = 0;
        data_in = 0;
        #20 
        rst_n = 1;    
        #20    
        $display("----------------- --------------");

        // Test case 1
        $display("==> Test case 1: feed 3 items, it should stop counting after two");       
        data_in = 1;           
        #10 
        data_in = 0;         
        #10 
        data_in = 1;           
        #10 
        data_in = 0;         
        #10 
        data_in = 1;           
        #10 
        data_in = 0;         
        #10       
        display;

         // Reset
        $display(" --------- Reset --------------");
        rst_n = 0;       
        data_in = 0;
        #20 
        rst_n = 1;
        #20         
        $display("----------------- --------------");

        // Test case 2
        $display("==> Test case 2: feed 1 item, it should not finish");
        data_in = 1;           
        #10 
        data_in = 0;  
        #10 
        display;   
        $display("==> Feed one more.. it should finish since the threshold is set at 2");
        data_in = 1;           
        #10 
        data_in = 0;  
        #10 
        display; 
        $display("==> Feed one more.. it should ignore it");
        data_in = 1;           
        #10 
        data_in = 0; 
        #10  
        display;     

        #100 
        $finish;
    end
    task display;
    #1 $display("data_in:%0h, data_cnt:%0h, finish:%0h, reset:%0h",
                 data_in, data_cnt, finish, rst_n);
  endtask

endmodule

Test run in simulation

Initialize
data_in:x, data_cnt:xxxx, finish:x, reset:x
----------- Reset --------------
----------------- --------------
==> Test case 1: feed 3 items, it should stop counting after two
data_in:0, data_cnt:2, finish:1, reset:1
 --------- Reset --------------
----------------- --------------
==> Test case 2: feed 1 item, it should not finish
data_in:0, data_cnt:1, finish:0, reset:1
==> Feed one more.. it should finish since the threshold is set at 2
data_in:0, data_cnt:2, finish:1, reset:1
==> Feed one more.. it should ignore it
data_in:0, data_cnt:2, finish:1, reset:1
puf/test_counter.v:89: $finish called at 315000 (1ps)