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)