ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

日常记录(73)、241寄存器模型

2022-03-09 20:04:04  阅读:210  来源: 互联网

标签:data new 73 uvm 寄存器 phase 241 my reg


我的DUT

  • 我只用了mem[0],它的地址是0x12345678。
  • 信号线一共就这几条、时钟、复位、地址、写数据线、读数据线、数据使能线、写读方向线。
  • 三段always,其中第一段没有用。
module dut (clk, rst_n, addr, w_data, r_data, data_valid, w_enable);
    input clk, rst_n;
    input [31:0] addr;
    input [15:0] w_data;
    input data_valid;
    input w_enable;
    output reg [15:0] r_data;

    reg [15:0] mem[3];
    reg [15:0] data;

    // mem function to control data
    always @(posedge clk) begin
        if (!rst_n) begin
            data <= '0;
        end else if (mem[0]==4'ha) begin
            data <= 16'haabb;
        end else if (mem[1]==4'hb) begin
            data <= 16'hbbcc;
        end else if (mem[2]==4'hc) begin
            data <= 16'hccdd;
        end else begin
            data <= '1;
        end
    end

    // signal to control mem write
    always @(posedge clk) begin
        if(!rst_n) begin
            mem[0] <= '0;
            mem[1] <= '1;
            mem[2] <= 16'b0101_0101_0101_0101;
        end else if (data_valid && w_enable) begin
            case (addr)
                32'h12345678: begin
                    mem[0] <= w_data;
                end
                32'h12345679: begin
                    mem[1] <= w_data;
                end
                32'h1234567a: begin
                end
                default: begin
                end
            endcase
        end
    end

    // signal to control mem read
    always @(posedge clk) begin
        if (!rst_n) begin
            r_data <= '0;
        end else if (data_valid && !w_enable) begin
            case (addr)
                32'h12345678: begin
                    r_data <= mem[0];
                end
                32'h12345679: begin
                    r_data <= '1;
                end
                32'h1234567a: begin
                    r_data <= mem[2];
                end
                default: begin
                end
            endcase
        end
    end

endmodule

test_top、interface

interface

interface bus_ctl (input bit clk);
    // nets
    logic rst_n, data_valid, w_enable;
    logic [31:0] addr;
    logic [15:0] w_data, r_data;
    // clocking
    clocking testbench_cb @(posedge clk);
        output rst_n, data_valid, w_enable;
        output addr;
        output w_data;
        input r_data;
    endclocking: testbench_cb
    // modports
    modport my_testbench(clocking testbench_cb, output rst_n);
endinterface: bus_ctl

test_top

  • 在testcase,或者env的调用接口上,是使用了test_top.bus_if的实例化调用。在使用过程中,直接可用cb,注意cb的非阻塞赋值。
  • modport也可以使用,如test_top.bus_if.my_testbench.rst_n,这个可以阻塞或者非阻塞。
  • 时钟生成与test_top即可,这个是dut和program公用。
`include "my_interface.sv"
module test_top ();
    bit clk;
    bus_ctl bus_if(clk);

    dut dut_inst(.clk(clk),
        .rst_n(bus_if.rst_n),
        .addr(bus_if.addr),
        .w_data(bus_if.w_data),
        .r_data(bus_if.r_data),
        .data_valid(bus_if.data_valid),
        .w_enable(bus_if.w_enable));

    test test_inst(bus_if);

    initial begin
        clk = 0;
        forever begin
            #1 clk = ~clk;
        end
    end
endmodule

program test (bus_ctl bus_if);
    import uvm_pkg::*;
    `include "testcase.sv"
    initial begin
        run_test("my_test");
    end
endprogram: test

testcase

  • 没有使用agent、env,直接上drv和seqr.用于测试reg_model
  • 首先是需要测试seqr和drv的通信,以及drv的读写协议是否能够操作dut。注意这个通信的trans必须有一个读写方向控制变量。而drv的数据是返回给req的。
  • 然后是建立寄存器模型进行读写控制。其中的发起者通过reg_model,使用read、write等,并配置,即可完成前后门访问。
  • 前门访问:发起者调用reg_model,reg_model生成seq,然后通过adapter转换,生成drv可用的trans,根据trans的方向、地址、数据,进行读写,返回时候给req即可。
  • 后门访问:发起者调用reg_model,reg_model可能是和DPI相关,然后通过路径(test_top.dut_inst.mem[0])等,直接就可以操作寄存器了。
  • 因此在前门访问中,需要set_sequencer,指定好seqr和adapter。
`include "my_seqr.sv"
`include "my_driver.sv"
`include "reg_model.sv"


class my_test extends uvm_test;
    `uvm_component_utils(my_test)
    virtual bus_ctl my_if;
    my_seq seq;
    my_driver drv;
    my_seqr seqr;

    my_block rm;
    my_block2 rm2;
    my_adapter adp;
    function new(string name="my_test", uvm_component parent);
        super.new(name, parent);
    endfunction: new

    function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        drv = my_driver::type_id::create("drv", this);
        seqr = my_seqr::type_id::create("seqr", this);
        uvm_config_db#(virtual bus_ctl)::set(this, "drv", "bus_if", test_top.bus_if);

        rm=my_block::type_id::create("name", this);
        rm.configure(null, "");
        rm.build();
        rm.lock_model();
        rm.reset();
        rm.set_hdl_path_root("test_top.dut_inst");

        rm2 = my_block2::type_id::create("rm2", this);
        rm2.configure(null, "");
        rm2.build();
        rm2.lock_model();
        rm2.reset();
        rm2.set_hdl_path_root("test_top");
        adp = new("apt");//type_id?
    endfunction: build_phase

    function void connect_phase(uvm_phase phase);
        drv.seq_item_port.connect(seqr.seq_item_export);
        rm.default_map.set_sequencer(seqr, adp);
        rm.default_map.set_auto_predict(1);

        rm2.default_map.set_sequencer(seqr, adp);
        rm2.default_map.set_auto_predict(1);
        check_config_usage();
    endfunction: connect_phase

    task run_phase(uvm_phase phase);
        uvm_status_e status;
        uvm_reg_data_t value;

        phase.raise_objection(this);
        seq = new("seq");
        seq.start(seqr);
        `uvm_info("INFO_ID", $sformatf("---------------------------------------------"), UVM_LOW)
        rm.reg1.read(status, value, UVM_FRONTDOOR);
        `uvm_info("INFO_ID", $sformatf("get data value %h", value), UVM_LOW)
        value = 'hbcde;
        rm.reg1.write(status, value, UVM_FRONTDOOR);
        `uvm_info("INFO_ID", $sformatf("get data value %h", value), UVM_LOW)
        rm.reg1.read(status, value, UVM_FRONTDOOR);
        `uvm_info("INFO_ID", $sformatf("get data value %h", value), UVM_LOW)
        `uvm_info("INFO_ID", $sformatf("---------------------------------------------"), UVM_LOW)
        value = 'h2345;
        rm.reg1.write(status, value, UVM_BACKDOOR);
        rm.reg1.read(status, value, UVM_BACKDOOR);
        `uvm_info("INFO_ID_READBACKDOOR_2345", $sformatf("get data value %h", value), UVM_LOW)
        `uvm_info("INFO_ID", $sformatf("---------------------------------------------"), UVM_LOW)
        value = 'h5678;
        rm.reg1.poke(status, value);
        rm.reg1.peek(status, value);
        `uvm_info("INFO_ID_PEEK_5678", $sformatf("peek get data value %h", value), UVM_LOW)
        `uvm_info("INFO_ID", $sformatf("---------------------------------------------"), UVM_LOW)
        value = 'haabb;
        rm2.blk2.reg1.write(status, value, UVM_FRONTDOOR);
        rm2.blk2.reg1.read(status, value, UVM_FRONTDOOR);
        `uvm_info("INFO_ID_FRONT2_aabb", $sformatf("get data value %h", value), UVM_LOW)
        `uvm_info("INFO_ID", $sformatf("---------------------------------------------"), UVM_LOW)
        value = 'hacbc;
        rm2.blk2.reg1.poke(status, value);
        rm2.blk2.reg1.peek(status, value);
        `uvm_info("INFO_ID_PEEK2_acbc", $sformatf("get data value %h", value), UVM_LOW)
        `uvm_info("INFO_ID", $sformatf("---------------------------------------------"), UVM_LOW)
        phase.drop_objection(this);

    endtask: run_phase

endclass: my_test

my_driver、my_sequencer

my_driver

class my_driver extends uvm_driver#(my_trans);
    `uvm_component_utils(my_driver)
    virtual bus_ctl my_if;
    event start_drive;

    function new(string name="my_driver", uvm_component parent);
        super.new(name, parent);
    endfunction: new

    function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        uvm_config_db#(virtual bus_ctl)::get(this, "", "bus_if", my_if);
    endfunction: build_phase

    task reset_phase(uvm_phase phase);
        phase.raise_objection(this);
        my_if.my_testbench.rst_n = 0;
        @(my_if.my_testbench.testbench_cb);
        my_if.my_testbench.rst_n = 1;
        @(my_if.my_testbench.testbench_cb);
        phase.drop_objection(this);
        -> start_drive;
    endtask: reset_phase

    task run_phase(uvm_phase phase);
        @(start_drive);
        while (1) begin
            seq_item_port.get_next_item(req);
            `uvm_info("DRIVER_GET", $sformatf("get data: %h, %h", req.address, req.data), UVM_LOW)
            drive();
            seq_item_port.item_done(rsp);
        end
    endtask: run_phase

    task drive();
        if(req.w_enable == 1) begin
            my_if.my_testbench.testbench_cb.w_data <= req.data;
            my_if.my_testbench.testbench_cb.addr <= req.address;
            my_if.my_testbench.testbench_cb.data_valid <= 1;
            my_if.my_testbench.testbench_cb.w_enable <= 1;
            @(my_if.my_testbench.testbench_cb);
            `uvm_info("DRIVER_WRITE", $sformatf("write: addr: %h, data: %h", req.address, req.data), UVM_LOW)
        end else begin
            my_if.my_testbench.testbench_cb.addr <= req.address;
            my_if.my_testbench.testbench_cb.data_valid <= 1;
            my_if.my_testbench.testbench_cb.w_enable <= 0;
            @(my_if.my_testbench.testbench_cb);
            req.data = my_if.r_data;
            `uvm_info("DRIVER_READ", $sformatf("read : addr: %h, data: %h", req.address, req.data), UVM_LOW)
        end
    endtask: drive
endclass: my_driver

my_sequencer\trans

-常规内容

class my_trans extends uvm_sequence_item;
    `uvm_object_utils(my_trans)
    rand int address;
    rand bit [15:0] data;
    rand bit w_enable;

    function new(string name="my_trans");
        super.new(name);
    endfunction: new
endclass: my_trans

class my_seq extends uvm_sequence#(my_trans);
    `uvm_object_utils(my_seq)

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

    task body();
        req = new("req");
        `uvm_do_with(req, {address==32'h12345678; data==16'habcd; w_enable=='1;})
        `uvm_do_with(req, {address==32'h12345678; data==16'habcd; w_enable=='0;})
    endtask: body
endclass: my_seq

typedef uvm_sequencer#(my_trans) my_seqr;

reg_model

  • 寄存器模型包括:field、reg、block、default_map至少四个要素。其中的field是一个位置,reg是多个寄存器位置的合集。block是reg的合集,需要一个default_map,同时可以包括其它的block。
  • uvm_reg\uvm_reg_block\uvm_reg_field是直接继承于uvm_object的。它们的build方法,不是phase的,需要手动调用。
  • my_reg是一个普通的16位reg,它被my_block包裹,形成一个reg_model。其中的reg1.configure配置了路径mem[0],后门访问用。reg进行build,是添加了reg_data,然后add_reg,说明了该reg的位置,前门访问用。
  • reg_file的实现,用于对reg_model进行路径配置。my_block_sub,是一个block,里面有file1,配置了dut_inst,和设置后门访问的configure进行组合,形成完整路径。
  • my_block2是包裹了my_block_sub的reg_model,它添加了my_block_sub以后,才应该进行block_model。里面有基地址,对应内部的偏移地址。
  • adapter:常规转换。
class my_reg extends uvm_reg;
    `uvm_object_utils(my_reg)
    uvm_reg_field reg_data;

    function new(string name="my_reg");
        // width of reg, option
        super.new(name, 16, UVM_NO_COVERAGE);
    endfunction: new

    function void build();
        reg_data = uvm_reg_field::type_id::create("reg1");
        // parent, size, lsb_pos, access, volatile, reset value, has_reset, is_rand, individually accessible
        reg_data.configure(this, 16, 0, "RW", 1, 0, 1, 1, 0);
    endfunction: build
endclass: my_reg

class my_block extends uvm_reg_block;
    `uvm_object_utils(my_block)
    my_reg reg1;

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

    function void build();
        default_map = create_map("default_map", 0, 2, UVM_LITTLE_ENDIAN, 0);
        reg1 = my_reg::type_id::create("reg1");//get_full_name
        reg1.configure(this, null, "mem[0]");
        reg1.build();
        default_map.add_reg(reg1, 32'h12345678, "RW");
    endfunction: build
endclass: my_block

class reg_file extends uvm_reg_file;
    `uvm_object_utils(reg_file)
    
    function new(string name="reg_file");
        super.new(name);
    endfunction: new
endclass: reg_file

class my_block_sub extends uvm_reg_block;
    `uvm_object_utils(my_block_sub)
    my_reg reg1;
    rand reg_file file1;

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

    function void build();
        /* file1 = reg_file::type_id::create("file1", ,get_full_name()); */
        file1 = reg_file::type_id::create("file1");
        file1.configure(this, null, "dut_inst");

        default_map = create_map("default_map", 0, 2, UVM_LITTLE_ENDIAN, 0);
        reg1 = my_reg::type_id::create("reg1");
        reg1.configure(this, file1, "mem[0]");
        reg1.build();
        default_map.add_reg(reg1, 32'h8, "RW");
    endfunction: build
endclass: my_block_sub

class my_block2 extends uvm_reg_block;
    `uvm_object_utils(my_block2)
    my_block_sub blk2;

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

    function void build();
        default_map = create_map("default_map", 0, 2, UVM_LITTLE_ENDIAN, 0);
        blk2 = my_block_sub::type_id::create("blk2");
        blk2.configure(this, "");
        blk2.build();
        default_map.add_submap(blk2.default_map, 32'h12345670);
        blk2.lock_model();
    endfunction: build
endclass: my_block2

class my_adapter extends uvm_reg_adapter;
    `uvm_object_utils(my_adapter)
    function new(string name="my_adapter");
        super.new(name);
    endfunction: new

    function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw);
        my_trans tr;
        tr = new("tr");
        tr.address = rw.addr;
        tr.data = rw.data;
        tr.w_enable = rw.kind == UVM_WRITE ? 1:0;
        return tr;
    endfunction: reg2bus

    function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw);
        my_trans tr;
        $cast(tr, bus_item);
        rw.addr = tr.address;
        rw.kind = tr.w_enable == 1 ? UVM_WRITE:UVM_READ;
        rw.data = tr.data;
        rw.status = UVM_IS_OK;
    endfunction: bus2reg
endclass: my_adapter

标签:data,new,73,uvm,寄存器,phase,241,my,reg
来源: https://www.cnblogs.com/bai2022/p/15986731.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有