EETOP 创芯网论坛 (原名:电子顶级开发网)

标题: 一种用AI生成完整的UVM Testbench的方法 [打印本页]

作者: xiatianla    时间: 2025-6-20 23:16
标题: 一种用AI生成完整的UVM Testbench的方法
虽然已经入夏,但一直阴雨绵绵,闲来无事,无意中发现一个用AI生成完整且可运行的UVM Testbench的方法。以一个FIFO为DUT,下面是AI生成对应的Testbench的一个总结,麻雀虽小,五脏俱全。关键点概述测试流程验证功能可扩展性


下面是生成的testbench的代码:(对天发誓,一个字母没改)


`timescale 1ns/1ps
`include "uvm_macros.svh"

import uvm_pkg::*;

// Interface for FIFO DUT
interface fifo_if(input bit clk);
    logic rst_n;
    logic wr_en;
    logic [31:0] data_in;
    logic rd_en;
    logic [31:0] data_out;
    logic full;
    logic empty;
    logic almost_full;
    logic almost_empty;
    logic overflow;
    logic underflow;
endinterface

// FIFO Transaction Item
class fifo_transaction extends uvm_sequence_item;
    rand bit [31:0] data;
    rand bit wr_en;
    rand bit rd_en;

    `uvm_object_utils_begin(fifo_transaction)
        `uvm_field_int(data, UVM_ALL_ON)
        `uvm_field_int(wr_en, UVM_ALL_ON)
        `uvm_field_int(rd_en, UVM_ALL_ON)
    `uvm_object_utils_end

    function new(string name = "fifo_transaction");
        super.new(name);
    endfunction

    constraint valid_ops {
        wr_en != rd_en;
    }
endclass

// FIFO Sequence
class fifo_sequence extends uvm_sequence #(fifo_transaction);
    `uvm_object_utils(fifo_sequence)

    rand int num_transactions = 20;
    fifo_transaction transactions[$];

    function new(string name = "fifo_sequence");
        super.new(name);
    endfunction

    task body();
        // First fill the FIFO
        for (int i = 0; i < 16; i++) begin
            fifo_transaction tx;
            `uvm_create(tx)
            tx.wr_en = 1;
            tx.rd_en = 0;
            assert(tx.randomize());
            transactions.push_back(tx);
            `uvm_send(tx)
        end

        // Wait for FIFO to be full
        #100;

        // Then empty the FIFO
        for (int i = 0; i < 16; i++) begin
            fifo_transaction tx;
            `uvm_create(tx)
            tx.wr_en = 0;
            tx.rd_en = 1;
            tx.data = 0; // Data doesn't matter for reads
            transactions.push_back(tx);
            `uvm_send(tx)
        end
    endtask
endclass

// FIFO Driver
class fifo_driver extends uvm_driver #(fifo_transaction);
    `uvm_component_utils(fifo_driver)

    virtual fifo_if vif;

    function new(string name, uvm_component parent);
        super.new(name, parent);
    endfunction

    function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        if (!uvm_config_db#(virtual fifo_if)::get(this, "", "vif", vif)) begin
            `uvm_fatal("NOVIF", "Virtual interface not set for driver")
        end
    endfunction

    task run_phase(uvm_phase phase);
        forever begin
            fifo_transaction tx;
            seq_item_port.get_next_item(tx);

            @(posedge vif.clk);
            vif.wr_en <= tx.wr_en;
            vif.rd_en <= tx.rd_en;
            vif.data_in <= tx.data;

            seq_item_port.item_done();
        end
    endtask
endclass

// FIFO Monitor
class fifo_monitor extends uvm_monitor;
    `uvm_component_utils(fifo_monitor)

    virtual fifo_if vif;
    uvm_analysis_port #(fifo_transaction) ap;

    function new(string name, uvm_component parent);
        super.new(name, parent);
    endfunction

    function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        ap = new("ap", this);
        if (!uvm_config_db#(virtual fifo_if)::get(this, "", "vif", vif)) begin
            `uvm_fatal("NOVIF", "Virtual interface not set for monitor")
        end
    endfunction

    task run_phase(uvm_phase phase);
        forever begin
            fifo_transaction tx = fifo_transaction::type_id::create("tx");

            @(posedge vif.clk);
            if (vif.wr_en && !vif.full) begin
                tx.wr_en = 1;
                tx.rd_en = 0;
                tx.data = vif.data_in;
                ap.write(tx);
            end
            if (vif.rd_en && !vif.empty) begin
                tx = fifo_transaction::type_id::create("tx");
                tx.wr_en = 0;
                tx.rd_en = 1;
                tx.data = vif.data_out;
                ap.write(tx);
            end
        end
    endtask
endclass

// FIFO Scoreboard
class fifo_scoreboard extends uvm_scoreboard;
    `uvm_component_utils(fifo_scoreboard)

    uvm_analysis_imp #(fifo_transaction, fifo_scoreboard) item_export;

    fifo_transaction write_q[$];
    fifo_transaction read_q[$];

    int write_count = 0;
    int read_count = 0;
    int match_count = 0;
    int mismatch_count = 0;

    function new(string name, uvm_component parent);
        super.new(name, parent);
    endfunction

    function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        item_export = new("item_export", this);
    endfunction

    function void write(fifo_transaction tx);
        if (tx.wr_en) begin
            write_q.push_back(tx);
            write_count++;
        end
        else if (tx.rd_en) begin
            read_q.push_back(tx);
            read_count++;
        end
    endfunction

    function void report_phase(uvm_phase phase);
        super.report_phase(phase);

        // Compare write and read transactions
        while (write_q.size() > 0 && read_q.size() > 0) begin
            fifo_transaction write_tx = write_q.pop_front();
            fifo_transaction read_tx = read_q.pop_front();

            if (write_tx.data !== read_tx.data) begin
                `uvm_error("SCOREBOARD", $sformatf("Data mismatch! Expected: 0x%0h, Actual: 0x%0h",
                          write_tx.data, read_tx.data))
                mismatch_count++;
            end
            else begin
                match_count++;
            end
        end

        // Check for transaction count mismatch
        if (write_count != read_count) begin
            `uvm_error("SCOREBOARD", $sformatf("Transaction count mismatch! Writes: %0d, Reads: %0d",
                      write_count, read_count))
        end

        `uvm_info("SCOREBOARD", $sformatf("Scoreboard Results: Matches=%0d, Mismatches=%0d, Writes=%0d, Reads=%0d",
                  match_count, mismatch_count, write_count, read_count), UVM_LOW)
    endfunction
endclass

// FIFO Agent
class fifo_agent extends uvm_agent;
    `uvm_component_utils(fifo_agent)

    fifo_driver driver;
    fifo_monitor monitor;
    uvm_sequencer #(fifo_transaction) sequencer;

    function new(string name, uvm_component parent);
        super.new(name, parent);
    endfunction

    function void build_phase(uvm_phase phase);
        super.build_phase(phase);

        monitor = fifo_monitor::type_id::create("monitor", this);

        if (get_is_active() == UVM_ACTIVE) begin
            driver = fifo_driver::type_id::create("driver", this);
            sequencer = uvm_sequencer#(fifo_transaction)::type_id::create("sequencer", this);
        end
    endfunction

    function void connect_phase(uvm_phase phase);
        super.connect_phase(phase);

        if (get_is_active() == UVM_ACTIVE) begin
            driver.seq_item_port.connect(sequencer.seq_item_export);
        end

        if (!uvm_config_db#(virtual fifo_if)::get(this, "", "vif", driver.vif)) begin
            `uvm_fatal("NOVIF", "Virtual interface not set for driver")
        end
        if (!uvm_config_db#(virtual fifo_if)::get(this, "", "vif", monitor.vif)) begin
            `uvm_fatal("NOVIF", "Virtual interface not set for monitor")
        end
    endfunction
endclass

// FIFO Environment
class fifo_env extends uvm_env;
    `uvm_component_utils(fifo_env)

    fifo_agent agent;
    fifo_scoreboard scoreboard;

    function new(string name, uvm_component parent);
        super.new(name, parent);
    endfunction

    function void build_phase(uvm_phase phase);
        super.build_phase(phase);

        agent = fifo_agent::type_id::create("agent", this);
        scoreboard = fifo_scoreboard::type_id::create("scoreboard", this);

        uvm_config_db#(uvm_active_passive_enum)::set(this, "agent", "is_active", UVM_ACTIVE);
    endfunction

    function void connect_phase(uvm_phase phase);
        super.connect_phase(phase);

        agent.monitor.ap.connect(scoreboard.item_export);
    endfunction
endclass

// Base Test
class base_test extends uvm_test;
    `uvm_component_utils(base_test)

    fifo_env env;
    fifo_sequence seq;

    function new(string name, uvm_component parent);
        super.new(name, parent);
    endfunction

    function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        env = fifo_env::type_id::create("env", this);
        seq = fifo_sequence::type_id::create("seq");
    endfunction

    task run_phase(uvm_phase phase);
        phase.raise_objection(this);
        seq.start(env.agent.sequencer);
        phase.drop_objection(this);
    endtask
endclass

// Basic Test
class basic_test extends base_test;
    `uvm_component_utils(basic_test)

    function new(string name = "basic_test", uvm_component parent = null);
        super.new(name, parent);
    endfunction

    function void build_phase(uvm_phase phase);
        super.build_phase(phase);
    endfunction

    task run_phase(uvm_phase phase);
        phase.raise_objection(this);
        `uvm_info(get_type_name(), "Starting basic FIFO test", UVM_LOW)

        seq.start(env.agent.sequencer);

        // Wait for all transactions to complete
        #200;

        phase.drop_objection(this);
    endtask
endclass

// Top Module
module top;
    import uvm_pkg::*;

    bit clk;
    bit rst_n;

    // Instantiate DUT interface
    fifo_if fif_if(clk);

    // Instantiate DUT
    FIFO #(
        .DATA_WIDTH(32),
        .FIFO_DEPTH(16),
        .ALMOST_FULL_THRESH(12),
        .ALMOST_EMPTY_THRESH(4)
    ) dut (
        .clk(clk),
        .rst_n(fif_if.rst_n),
        .wr_en(fif_if.wr_en),
        .data_in(fif_if.data_in),
        .rd_en(fif_if.rd_en),
        .data_out(fif_if.data_out),
        .full(fif_if.full),
        .empty(fif_if.empty),
        .almost_full(fif_if.almost_full),
        .almost_empty(fif_if.almost_empty),
        .overflow(fif_if.overflow),
        .underflow(fif_if.underflow)
    );

    // Clock generation
    initial begin
        clk = 0;
        forever #5 clk = ~clk;
    end

    // Reset generation
    initial begin
        fif_if.rst_n = 0;
        #20 fif_if.rst_n = 1;
    end

    // UVM test setup
    initial begin
        uvm_config_db#(virtual fifo_if)::set(null, "uvm_test_top.env*", "vif", fif_if);
        run_test("basic_test");
    end

    // Final check
    final begin
        if (uvm_report_server::get_server().get_severity_count(UVM_FATAL) > 0) begin
            $display("Simulation finished with UVM_FATAL errors");
            $finish(2);
        end
        else if (uvm_report_server::get_server().get_severity_count(UVM_ERROR) > 0) begin
            $display("Simulation finished with UVM_ERROR errors");
            $finish(1);
        end
        else begin
            $display("Test passed successfully");
            $finish(0);
        end
    end
endmodule

完整代码
完整版DUT,Testbench和Testcase 代码打包文件: ( , 下载次数: 12 )



实现方式
1. AIDEV Project Workspace
2. 输入dut fifo的功能需求,选择生成和编译选项,填入额外的test需求,提交,坐等代码生成,发入你邮箱。

                               
登录/注册后可看大图



作者: Pwny    时间: 2025-6-22 09:54
顶一顶
作者: llwdahai    时间: 2025-6-24 17:10





欢迎光临 EETOP 创芯网论坛 (原名:电子顶级开发网) (https://bbs.eetop.cn/) Powered by Discuz! X3.5