텐서 곱셈 모듈의 UVM 테스트벤치를 작성하라고 해 보았음

그런 다음에 클로드3 소넷이랑 붙던데 답변이 끝도없이 길게 나왔음

말 안 해도 자체적으로 Step by step 적용하네
몇개 좀 이상한 부분이 있긴 한데 HDL은 자료가 워낙에 적어서 뭐 그러려니한듯

--------

Creating a UVM testbench for a synthesizable Verilog module that performs tensor multiplication requires several steps. Here, I'll guide you through the process of setting up a basic UVM testbench structure that you can use to stimulate and verify a tensor multiplication module.

### Step-by-Step Guide to Create a UVM Testbench

#### 1. **Define the Testbench Architecture**

First, define the overall structure of your UVM testbench. The typical components include:

- **DUT (Device Under Test):** The Verilog module performing tensor multiplication.
- **Testbench:** Contains instances of UVM components like agents, monitors, and scoreboards.
- **Agent:** Manages the interface with the DUT, including a sequencer, driver, and monitor.
- **Environment:** Encloses all the agents and provides configuration.
- **Test:** Defines and runs sequences of transactions.

#### 2. **Identify the Interface**

Suppose your tensor multiplication module has the following interface:

```verilog
module tensor_mult #(
    parameter DATA_WIDTH = 8,
    parameter A_DIM1 = 4, A_DIM2 = 3, B_DIM2 = 2
)(
    input  logic                         clk,
    input  logic                         rst,
    input  logic [A_DIM1*A_DIM2*DATA_WIDTH-1:0] A,
    input  logic [A_DIM2*B_DIM2*DATA_WIDTH-1:0] B,
    output logic [A_DIM1*B_DIM2*DATA_WIDTH-1:0] C,
    output logic                         valid
);
```

#### 3. **Create the Interface**

Create a UVM interface to communicate with the DUT. For instance:

```systemverilog
interface tensor_mult_if(
    input logic clk
);

    logic rst;
    logic [A_DIM1*A_DIM2*DATA_WIDTH-1:0] A;
    logic [A_DIM2*B_DIM2*DATA_WIDTH-1:0] B;
    logic [A_DIM1*B_DIM2*DATA_WIDTH-1:0] C;
    logic valid;

    modport DUT(
        input rst, A, B,
        output C, valid
    );

endinterface
```

#### 4. **Build the UVM Components**

##### a. **Sequence Item**

This represents a single operation of tensor multiplication.

```systemverilog
class tensor_mult_item extends uvm_sequence_item;

    `uvm__utils(tensor_mult_item)

    rand bit [A_DIM1*A_DIM2*DATA_WIDTH-1:0] A;
    rand bit [A_DIM2*B_DIM2*DATA_WIDTH-1:0] B;
    bit [A_DIM1*B_DIM2*DATA_WIDTH-1:0] C;

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

endclass
```

##### b. **Driver**

Drives the inputs of the DUT based on the sequence item.

```systemverilog
class tensor_mult_driver extends uvm_driver #(tensor_mult_item);

    `uvm_component_utils(tensor_mult_driver)

    tensor_mult_if vif;

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

    virtual function void build_phase(uvm_phase phase);
        if (!uvm_config_db #(virtual tensor_mult_if)::get(this, "", "vif", vif))
            `uvm_fatal("NOVIF", "virtual interface must be set for: " .name)
    endfunction

    virtual task run_phase(uvm_phase phase);
        forever begin
            seq_item_port.get_next_item(req);
            vif.A <= req.A;
            vif.B <= req.B;
            wait (vif.valid === 1'b1);
            req.C = vif.C;
            seq_item_port.item_done();
        end
    endtask

endclass
```

##### c. **Monitor**

Observes outputs from the DUT and reports them.

```systemverilog
class tensor_mult_monitor extends uvm_monitor;

    `uvm_component_utils(tensor_mult_monitor)

    tensor_mult_if vif;
    uvm_analysis_port #(tensor_mult_item) item_collected_port;

    function new(string name, uvm_component parent);
        super.new(name, parent);
        item_collected_port = new("item_collected_port", this);
    endfunction

    virtual function void build_phase(uvm_phase phase);
        if (!uvm_config_db #(virtual tensor_mult_if)::get(this, "", "vif", vif))
            `uvm_fatal("NOVIF", "virtual interface must be set for: " .name)
    endfunction

    virtual task run_phase(uvm_phase phase);
        tensor_mult_item item;
        forever begin
            wait (vif.valid === 1'b1);
            item = tensor_mult_item::type_id::create("item");
            item.C = vif.C;
            item_collected_port.write(item);
        end
    endtask

endclass
```

##### d. **Agent**

Combines the driver and monitor.

```systemverilog
class tensor_mult_agent extends uvm_agent;

    `uvm_component_utils(tensor_mult_agent)

    tensor_mult_driver driver;
    tensor_mult_monitor monitor;
    virtual tensor_mult_if vif;

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

    virtual function void build_phase(uvm_phase phase);
        if (!uvm_config_db #(virtual tensor_mult_if)::get(this, "", "vif", vif))
            `uvm_fatal("NOVIF", "virtual interface must be set for: " .name)
        driver = tensor_mult_driver::type_id::create("driver", this);
        monitor = tensor_mult_monitor::type_id::create("monitor", this);
    endfunction

    virtual function void connect_phase(uvm_phase phase);
        driver.seq_item_port.connect(get_sequencer().seq_item_export);
        driver.vif = vif;
        monitor.vif = vif;
    endfunction

endclass
```

##### e. **Environment**

Encapsulates the agent.

```systemverilog
class tensor_mult_env extends uvm_env;

    `uvm_component_utils(tensor_mult_env)

    tensor_mult_agent agent;

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

    virtual function void build_phase(uvm_phase phase);
        agent = tensor_mult_agent::type_id::create("agent", this);
        if (!uvm_config_db #(virtual tensor_mult_if)::get(this, "", "vif", agent.vif))
            `uvm_fatal("NOVIF", "virtual interface must be set for the agent")
    endfunction

endclass
```

##### f. **Test**

Defines the test scenario.

```systemverilog
class tensor_mult_test extends uvm_test;

    `uvm_component_utils(tensor_mult_test)

    tensor_mult_env env;
    virtual tensor_mult_if vif;

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

    virtual function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        env = tensor_mult_env::type_id::create("env", this);
        if (!uvm_config_db #(virtual tensor_mult_if)::get(this, "", "vif", vif))
            `uvm_fatal("NOVIF", "virtual interface must be set for the environment")
    endfunction

    virtual task run_phase(uvm_phase phase);
        super.run_phase(phase);
        tensor_mult_item item;
        uvm_config_db #(virtual tensor_mult_if)::set(this, "env.agent", "vif", vif);
        phase.raise_ion(this);
        // Example sequence
        item = tensor_mult_item::type_id::create("item");
        item.A = {8'd1, 8'd2, 8'd3, 8'd4, 8'd5, 8'd6, 8'd7, 8'd8, 8'd9, 8'd10, 8'd11, 8'd12};
        item.B = {8'd1, 8'd2, 8'd3, 8'd4, 8'd5, 8'd6};
        uvm_do_with(item, {});
        wait (vif.valid === 1'b1);
        phase.drop_ion(this);
    endtask

endclass
```

#### 5. **Top Module**

Connects the DUT with the testbench using the interface.

```systemverilog
module tb_top;

    logic clk = 0;
    always #5 clk = ~clk;

    tensor_mult_if vif(clk);

    tensor_mult #(
        .DATA_WIDTH(8),
        .A_DIM1(4), .A_DIM2(3), .B_DIM2(2)
    ) DUT (
        .clk(clk),
        .rst(vif.rst),
        .A(vif.A),
        .B(vif.B),
        .C(vif.C),
        .valid(vif.valid)
    );

    initial begin
        uvm_config_db #(virtual tensor_mult_if)::set(null, "uvm_test_top.env.agent", "vif", vif);
        run_test("tensor_mult_test");
    end

endmodule
```

This testbench is a basic framework to stimulate and verify a tensor multiplication module in SystemVerilog using UVM. You can expand this by adding more complex sequences, coverage, and scoreboards to fully verify the module's functionality.