내머리속은이런걸로 2024. 7. 10. 12:16

ALU UVM 검증

  • input [31:0] a
  • input [31:0] b
  • input op
  • output [31:0] result
  • op : 1'b0 → result = a + b
  • op : 1'b1 result = a - b

 

adder.sv

`timescale 1ns / 1ps

module adder(
    input logic [31:0] a,
    input logic [31:0] b,
    input logic op,
    output logic [31:0] result
    );

    always_comb begin
        case (op)
            1'b0: result = a + b; 
            1'b1: result = a - b;
        endcase
    end
endmodule

 

tb_adder.sv

`timescale 1ns / 1ps
`include "uvm_macros.svh"
import uvm_pkg::*;

interface adder_interface;
    logic [31:0] a;
    logic [31:0] b;
    logic  op;
    logic [31:0] result;
endinterface //adder_interface

class seq_item extends uvm_sequence_item;  // super class 상속
    rand bit [31:0] a;
    rand bit [31:0] b;
    rand bit op;
    bit [31:0] result;
    
    constraint adder_c {a>b;}

    function new(input string name = "seq_item");   // seq_item : string name
        super.new(name); // 부모 class
    endfunction //new()

    // uvm 등록 (field 값으로 uvm 등록)
    `uvm_object_utils_begin(seq_item)   // seq_item : class name
        `uvm_field_int(a, UVM_DEFAULT)
        `uvm_field_int(b, UVM_DEFAULT)
        `uvm_field_int(op, UVM_DEFAULT)
        `uvm_field_int(result, UVM_DEFAULT)
    `uvm_object_utils_end

endclass //seq_item extend uvm_sequence_item

class adder_sequence extends uvm_sequence; // generator
    `uvm_object_utils(adder_sequence)   // add uvm factory, adder_sequence : class name

    seq_item adder_seq_item;

    function new(input string name = "adder_sequence");
        super.new(name);        
    endfunction //new()

    virtual task body(); // virtual : 다형성 기능(subclass)
        adder_seq_item = seq_item::type_id::create("SEQ_ITEM"); // create instance
        repeat(1000) begin
            start_item(adder_seq_item);
            adder_seq_item.randomize();
            `uvm_info("SEQ", "Data send to Driver", UVM_NONE);
            finish_item(adder_seq_item);
        end
    endtask
endclass // extends superClass

class adder_driver extends uvm_driver #(seq_item);
    `uvm_component_utils(adder_driver) // add factory
    
    virtual adder_interface adderIntf;
    seq_item adder_seq_item;
    
    function new(input string name = "adder_driver", uvm_component c);
        super.new(name, c);
    endfunction //new()

    virtual function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        adder_seq_item = seq_item::type_id::create("SEQ_ITEM", this);
        if (!uvm_config_db#(virtual adder_interface)::get(this, "", "adderIntf", adderIntf)) begin
            `uvm_fatal(get_name(), "Unable to access adder interface");
        end
    endfunction

    virtual function void start_of_simulation_phase(uvm_phase phase);
        $display("display start of simulation phase!");
    endfunction

    virtual task run_phase(uvm_phase phase);
        $display("display run phase!");
        forever begin
            #10;
            seq_item_port.get_next_item(adder_seq_item);
                adderIntf.a = adder_seq_item.a;
                adderIntf.b = adder_seq_item.b;
                adderIntf.op = adder_seq_item.op;
                `uvm_info("DRV", "Send data to DUT", UVM_NONE);
            seq_item_port.item_done();
        end
    endtask

endclass //adder_driver extends uvm_driver #(seq_item)

class adder_monitor extends uvm_monitor;
    `uvm_component_utils(adder_monitor) // add factory

    uvm_analysis_port #(seq_item) send;
    virtual adder_interface adderIntf;
    seq_item adder_seq_item;

    function new(input string name = "adder_monitor", uvm_component c);
        super.new(name, c);
        send = new("WRITE", this);
    endfunction //new()

    virtual function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        adder_seq_item = seq_item::type_id::create("SEQ_ITEM", this);
        if (!uvm_config_db#(virtual adder_interface)::get(this, "", "adderIntf", adderIntf)) begin
            `uvm_fatal(get_name(), "Unable to access adder interface");
        end
    endfunction

    virtual task run_phase(uvm_phase phase);
        forever begin
            #10;
            adder_seq_item.a = adderIntf.a;
            adder_seq_item.b = adderIntf.b;
            adder_seq_item.op = adderIntf.op;
            adder_seq_item.result = adderIntf.result;
            `uvm_info("MON", "send data to Scoreboard", UVM_NONE);
            send.write(adder_seq_item);
        end
    endtask
endclass //adder_monitor extends uvm_monitor

class adder_scoreboard extends uvm_scoreboard;
    `uvm_component_utils(adder_scoreboard)

    uvm_analysis_imp #(seq_item, adder_scoreboard) recv;

    function new(input string name = "adder_scoreboard", uvm_component c);
        super.new(name, c);
        recv = new("READ", this);
    endfunction

    virtual function void write(seq_item data);
        `uvm_info("SCB", "Data received from Monitor", UVM_NONE);
        
        if((data.op == 1'b0) && ((data.a + data.b) == data.result)) begin
            `uvm_info("SCB", $sformatf("Pass!, %d + %d = %d", data.a, data.b, data.result), UVM_NONE);
        end
        else if((data.op == 1'b1) && ((data.a - data.b) == data.result)) begin
            `uvm_info("SCB", $sformatf("Pass!, %d - %d = %d", data.a, data.b, data.result), UVM_NONE);
        end
        else begin
            `uvm_error("SCB", $sformatf("Fail!, %d + %d = %d", data.a, data.b, data.result));
        end
        data.print(uvm_default_line_printer);
    endfunction
endclass

class adder_agent extends uvm_agent;
    `uvm_component_utils(adder_agent)

    function new(input string name = "adder_agent", uvm_component c);
        super.new(name, c);
    endfunction //new()

    adder_monitor adderMonitor;
    adder_driver adderDriver;
    uvm_sequencer #(seq_item) adderSequencer;

    virtual function void build_phase(uvm_phase phase); // make instance
        super.build_phase(phase);
        adderMonitor = adder_monitor::type_id::create("MON", this);
        adderDriver = adder_driver::type_id::create("DRV", this);
        adderSequencer = uvm_sequencer#(seq_item)::type_id::create("SQR", this);
    endfunction

    virtual function void connect_phase(uvm_phase phase);
        super.connect_phase(phase);
        adderDriver.seq_item_port.connect(adderSequencer.seq_item_export);
    endfunction

endclass //adder_agent extends uvm_agent

class adder_env extends uvm_env;
    `uvm_component_utils(adder_env)

    function new(input string name = "adder_env", uvm_component c);
        super.new(name, c);
    endfunction //new()

    adder_scoreboard adderScoreboard;
    adder_agent adderAgent;

    virtual function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        adderScoreboard = adder_scoreboard::type_id::create("SCB", this);
        adderAgent = adder_agent:: type_id::create("AGENT", this);  // this : use in this class
    endfunction

    virtual function void connect_phase(uvm_phase phase);
        super.connect_phase(phase);
        adderAgent.adderMonitor.send.connect(adderScoreboard.recv);
    endfunction
endclass //adder extends uvm_env

class adder_test extends uvm_test;
    `uvm_component_utils(adder_test);

    function new(input string name = "adder_test", uvm_component c);
        super.new(name, c);
    endfunction //new()

    adder_sequence adderSequence;
    adder_env adderEnv;

    virtual function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        adderSequence = adder_sequence::type_id::create("SEQ", this);
        adderEnv = adder_env::type_id::create("ENV", this);
    endfunction

    virtual task run_phase(uvm_phase phase);
        phase.raise_objection(this);
        adderSequence.start(adderEnv.adderAgent.adderSequencer);
        phase.drop_objection(this);
    endtask
endclass //adder_test extends uvm_test

module tb_Adder ();

    adder_interface adderIntf();
    adder_test adderTest;

    adder dut (
        .a(adderIntf.a),
        .b(adderIntf.b),
        .op(adderIntf.op),
        .result(adderIntf.result)
    );

    initial begin
        adderTest = new("Adder UVM Verification", null); 
        uvm_config_db#(virtual adder_interface)::set(null, "*", "adderIntf", adderIntf);
        run_test();
    end
endmodule