Skip to content

Final project - PUF module

Code

`timescale 1ns/1ps

module puf_bit ( 
    input wire[7:0] challenge,     // the PUF challenge
    input wire clk,                // the clock
    input wire rst_n,              // reset 
    input wire enable,             // enable
    output wire response,          // the response to the challenge
    output wire done               // end of the race
);

    localparam n_ro = 32;                                               // we have 2 series of 16 ROs, with a 7 inverters chain in each
    localparam n_half = n_ro / 2;

    wire[n_ro-1:0] ro_out;                                              // the outputs of the 32 ROs
    wire mux_out_1;                                                     // the output of the first MUX
    wire mux_out_2;                                                     // the output of the second MUX
    /* verilator lint_off UNUSEDSIGNAL */
    wire[15:0] cnt_out_1;                                               // the output of the first counter
    wire[15:0] cnt_out_2;                                               // the output of the second counter
    /* verilator lint_on UNUSEDSIGNAL */
    wire finish_1;                                                      // a flag indicating the first counter has reached its threshold
    wire finish_2;                                                      // a flag indicating the second counter has reached its threshold

    genvar i;

    // This block generates 32 ROs
    generate
        for (i = 0; i < n_ro; i = i + 1) begin : ro_gen
            ro ro_inst (.enable(enable), .endOfChain(ro_out[i]));
        end
    endgenerate

    mux mux_1(.ro_inputs(ro_out[n_half-1:0]), .challenge(challenge[3:0]), .out(mux_out_1));           // setup the first MUX, it gets data from the first 16 ROs
    mux mux_2(.ro_inputs(ro_out[n_ro-1:n_half]), .challenge(challenge[7:4]), .out(mux_out_2));        // setup the second MUX, it gets data from the second 16 ROs


    `ifndef SYNTHESIS
    counter #(.THRESHOLD(16'b0000000011111111)) cnt_1(.clk(clk), .rst_n(rst_n), .data_in(mux_out_1),
                                                      .data_cnt(cnt_out_1), .finish(finish_1));       // setup the first counter, it gets data from first MUX
    counter #(.THRESHOLD(16'b0000000011111111)) cnt_2(.clk(clk), .rst_n(rst_n), .data_in(mux_out_2), 
                                                      .data_cnt(cnt_out_2), .finish(finish_2));       // setup the second counter, it gets data from the second MUX
    `else 
    counter #(.THRESHOLD(16'b1111111111111111)) cnt_1(.clk(clk), .rst_n(rst_n), .data_in(mux_out_1),
                                                      .data_cnt(cnt_out_1), .finish(finish_1));       // setup the first counter, it gets data from first MUX
    counter #(.THRESHOLD(16'b1111111111111111)) cnt_2(.clk(clk), .rst_n(rst_n), .data_in(mux_out_2), 
                                                      .data_cnt(cnt_out_2), .finish(finish_2));       // setup the second counter, it gets data from the second MUX      
    `endif  


    arbiter race_arb(.clk(clk), .rst_n(rst_n), .data_in1(finish_1), .data_in2(finish_2), 
                     .data_out(response), .finish(done));                                             // setup the arbiter, it gets data from both counters

endmodule 

Lint

verilator --lint-only -Wall -Ilib puf/puf_bit.v puf/ro.v puf/mux.v puf/counter.v puf/arbiter.v  config.vlt
- 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.110 MB sources in 6 modules, into 2.108 MB in 5 C++ files needing 0.000 MB
- Verilator: Walltime 0.133 s (elab=0.001, cvt=0.099, bld=0.000); cpu 0.132 s on 1 threads; alloced 56.348 MB

Test harness

`timescale 1ns/1ps

module test_puf_bit;  
    // Inputs are reg (we drive them)
    reg[7:0] challenge;                       // the proposed PUF challenge
    reg clk;
    reg rst_n;
    reg enable;

    // Outputs are wire (DUT drives them)
    wire response;                            // the PUF response to the challenge
    wire done;

    // Instantiate Device Under Test
    puf_bit muPuf (
        .challenge(challenge),
        .clk(clk),
        .rst_n(rst_n),
        .enable(enable),
        .response(response),
        .done(done)
    );

    initial clk = 0;

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

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

         // Initialize
        $display("==> Initialize ");
        clk = 0;  
        enable = 0;      

        // Reset
        $display("==> Reset ");
        enable = 0;  
        rst_n = 0;           
        #20                 

        // Test case 1
        $display("==> Test case 1");  
        rst_n = 1;  
        challenge = 8'b11111111;    
        enable = 1;      
        #40000         
        print_status;

        // Reset
        $display("==> Reset ");
        enable = 0;  
        rst_n = 0;           
        #20  

        // Test case 2
        $display("==> Test case 2");  
        rst_n = 1;  
        challenge = 8'b00000000;   
        enable = 1;      
        #40000         
        print_status;

        // Reset
        $display("==> Reset ");
        enable = 0;  
        rst_n = 0;           
        #20               

        // Test case 3
        $display("==> Test case 3");  
        rst_n = 1;  
        challenge = 8'b00110011;   
        enable = 1;      
        #40000       
        print_status;

        #100 
        $finish;
    end
    task print_status;
    #1 $display("enable:%0b, rst_n:%0b, challenge:%08b, response:%08b, done:%0b",
                 enable, rst_n, challenge, response, done);
  endtask

endmodule

Test run in simulation

==> Initialize 
==> Reset 
==> Test case 1
enable:1, rst_n:1, challenge:11111111, response:00000001, done:1
==> Reset 
==> Test case 2
enable:1, rst_n:1, challenge:00000000, response:00000001, done:1
==> Reset 
==> Test case 3
enable:1, rst_n:1, challenge:00110011, response:00000001, done:1
puf/test_puf_bit.v:82: $finish called at 120163000 (1ps)