Simulation et testbench

Principe du testbench

Un testbench est un module Verilog sans ports physiques, destiné uniquement à la simulation. Il instancie le circuit à vérifier (Device Under Test, DUT) et génère des stimuli.

┌──────────────────────────────────────┐
│  Testbench (tb_top.v)                │
│                                      │
│  clk_gen   ──────────────────────┐   │
│  rst_seq   ──────────────────┐   │   │
│  sig_sim   ─────────────┐    │   │   │
│                         ▼    ▼   ▼   │
│              ┌──────────────────────┐│
│              │   DUT (top_nexys4)   ││
│              └──────────────────────┘│
│                         │            │
│  monitor   ◄────────────┘            │
└──────────────────────────────────────┘

Testbench complet

tb_top.v
`timescale 1ns/1ps

module tb_top;

    // ── Paramètres de simulation ──────────────────────────────
    localparam CLK_PERIOD  = 10;   // 100 MHz → 10 ns
    localparam SIG_PERIOD  = 50;   // signal analogique simulé 20 MHz → 50 ns
    localparam N_DIV       = 16;   // rapport de division
    localparam EXPECTED_T  = SIG_PERIOD * N_DIV; // 800 ns attendus

    // ── Déclarations ──────────────────────────────────────────
    reg  clk_100mhz;
    reg  rst_btn;
    reg  sig_bin_sim;      // simule la sortie du comparateur
    wire rising_pulse;
    wire clk_out;

    // ── Horloge système 100 MHz ───────────────────────────────
    initial clk_100mhz = 1'b0;
    always  #(CLK_PERIOD/2) clk_100mhz = ~clk_100mhz;

    // ── Signal analogique simulé à 20 MHz ─────────────────────
    // (on court-circuite le XADC qui n'est pas simulable directement)
    initial sig_bin_sim = 1'b0;
    always  #(SIG_PERIOD/2) sig_bin_sim = ~sig_bin_sim;

    // ── Instanciation du détecteur de front (DUT partiel) ─────
    edge_detector u_edge (
        .clk         (clk_100mhz),
        .rst_n       (~rst_btn),
        .sig_in      (sig_bin_sim),
        .rising_edge (rising_pulse),
        .falling_edge()
    );

    // ── Instanciation du diviseur (DUT) ───────────────────────
    freq_divider #(.N(N_DIV)) u_div (
        .clk          (clk_100mhz),
        .rst_n        (~rst_btn),
        .rising_pulse (rising_pulse),
        .clk_out      (clk_out)
    );

    // ── Séquence de contrôle ──────────────────────────────────
    initial begin
        rst_btn = 1'b1;          // reset actif
        #50;
        rst_btn = 1'b0;          // relâcher le reset
        #20000;                  // simuler 20 µs
        $display("[INFO] Fin de simulation à %0t ns", $time);
        $finish;
    end

    // ── Vérification automatique de la période ─────────────────
    real t_rise1, t_rise2, measured_T;

    initial begin
        @(posedge (~rst_btn));       // attendre fin de reset
        @(posedge clk_out);          // ignorer le 1er front (init)
        @(posedge clk_out); t_rise1 = $realtime;
        @(posedge clk_out); t_rise2 = $realtime;
        measured_T = t_rise2 - t_rise1;

        $display("──────────────────────────────────────────");
        $display("Période mesurée : %0.1f ns", measured_T);
        $display("Période attendue: %0d ns", EXPECTED_T);
        if (measured_T == EXPECTED_T)
            $display("[PASS] Diviseur ÷%0d correct.", N_DIV);
        else
            $display("[FAIL] Période incorrecte !");
        $display("──────────────────────────────────────────");
    end

    // ── Dump VCD pour visualisation GTKWave ───────────────────
    initial begin
        $dumpfile("sim_div_freq.vcd");
        $dumpvars(0, tb_top);
    end

endmodule

Lancer la simulation dans Vivado

  1. Ajouter tb_top.v via Add Sources → Add simulation sources.

  2. Dans le Flow Navigator : Run Simulation → Run Behavioral Simulation.

  3. Dans la fenêtre Tcl Console, vérifier les messages [PASS].

  4. Dans la fenêtre Waveform, ajouter les signaux sig_bin_sim, rising_pulse et clk_out pour visualiser le chronogramme.

Résultats attendus en simulation

Signal

Fréquence attendue

Période attendue

sig_bin_sim (signal simulé)

20 MHz

50 ns

rising_pulse

20 MHz (1 pulse/période)

50 ns (durée : 10 ns)

clk_out (sortie divisée)

1,25 MHz

800 ns

Note

En simulation, le signal analogique est remplacé par un carré parfait. Sur carte réelle avec XADC, la fréquence effective sera plus basse (voir Acquisition analogique — XADC).

See also

Restructuration du dépôt Git pour les recommandations d’organisation du dépôt Git contenant ces fichiers Verilog.