4. UVM -- TLM通信机制与平台的connect

1. 事务 tansaction

事务 tansaction 是一系列具有一定关系和功能的数据集合。

简单来说,一个tansaction就是把具有某一特定功能的一组信息封装在一起而成为的一个类;

事务是UVM平台中信息交互的基本单元

1.1. 从uvm_sequence_item扩展事务

1.2. 受约束的随机事务

2. UVM TLM通信机制

TLM是Transaction Level Modeling(事务级建模)的缩写起源于SystemC的一种通信标准。

所谓 transaction level是DUT中各个模块之间信号线级别的通信来说的。

2.1. TLM 原理

2.2. 常用的UVM端口

2.2.1. 端对端模式

2.2.1.1. port
  • try_ 常用来是否成功为function,
  • can_ 常用来是否可传输,为function,非阻塞类型使用;
  • put/get 为task;

2.2.1.2. import (使用时要与put端口类型一致)

2.2.1.3. export (中间端口使用)

2.2.2. 方法模式

2.2.2.1. put模式实例

2.2.2.2. get模式实例

2.2.2.3. FIFO模式

  • FIFO的本质是一块缓存加两个IMP。

  • 在monitor与FIFO的连接关系中,monitor中依然是 analysis_port,FIF0中是uvm_analysis_imp,数据流和控制流的方向相同。

  • 在scoreboard与FIFO的连接关系中,scoreboard中使 blocking_get_port端口。

  • fifo 内建write task,ap口可以直接调用,将Transaction 发送 fifo;

  • 而从fifo取Transaction ,我们一般用blocking_get_port端口连接后用get();

  • fifo方法实例

2.2.3. 一对多模式

  • uvm_analysis_port #(T) ap;
  • uvm_analysis_export #(T) aexp;
  • uvm_analysis_imp #(my0_seq_item, my_scoreboard) aimp

注意1:

  • scoreboard除了接收monitor的数据之外,还要接收reference model的数据。
  • 相应的scoreboard就要再添加一个uvm_analysis_imp的IMP如 model_imp。
  • 此时问题就出现了,由于接收到的两路数据应该做不同的处理,以这个新的IMP也要有一个write任务与其对应。但是write只有一个怎么办?
  • UVM考虑到了这种情况,它定义了一个uvm_analysis_imp_decl来解决这个问题,其使用方式为:

img

3. demo -- 平台组件的connect

  • test_pkg.sv
//-----------------------------------------------
//@ my_test_pkg
//@ Version : V0.1
//@ Wesley 2022.04.10
//-----------------------------------------------
`ifndef my_test_pkg__SV
`define my_test_pkg__SV

`include "my_intf.sv"

package my_test_pkg;
    import uvm_pkg::*;
    `include "uvm_macros.svh"

    `include "my_env_list.incl"
    `include "my_seq_list.incl"
    //`include "my_vseq_list.incl"
    `include "my_callbacks.sv"

    `include "my_base_test.svh"
endpackage: my_test_pkg

`endif // my_test_pkg__SV

  • test_top.sv
//-----------------------------------------------
//@ test_top
//@ Version : V0.1
//@ Wesley 2022.04.10
//-----------------------------------------------
module test_top;
    import uvm_pkg::*;
    `include "uvm_macros.svh"
    import my_test_pkg::*;
  
    logic clk     = 0;
    logic reset_n = 0;
    //interface
    my_intf vif( .clk(clk), .reset_n(reset_n));
  
    // DUT - a 16550 UART:
    dut DUT ( .clk          ( clk               ),
              .rst_n        ( reset_n           ),
              .bus_cmd_valid( vif.bus_cmd_valid ),
              .bus_op       ( vif.bus_op        ),
              .bus_addr     ( vif.bus_addr      ),
              .bus_wr_data  ( vif.bus_wr_data   ),
              .bus_rd_data  ( vif.bus_rd_data   ),
              .rxd          ( vif.rxd           ),
              .rx_dv        ( vif.rx_dv         ),
              .txd          ( vif.txd           ),
              .tx_en        ( vif.tx_en         )
            );
    // clock/reset
    always #5ns clk = ~clk;
    initial begin
        clk     = 0;
        reset_n = 0;
        repeat(10) @(posedge clk);
        reset_n = 1;
	      `uvm_info (" TEST_TOP ", $sformatf("clk = 0x%h , resetn = 0x%h", clk, reset_n), UVM_MEDIUM)
    end
  
    // UVM virtual interface handling and run_test()
    initial begin
        // virtual interface
        uvm_config_db #(virtual my_intf)::set(null, "uvm_test_top*", "vif.BUS", vif);
        uvm_config_db #(virtual my_intf)::set(null, "uvm_test_top*", "vif.MOD", vif);
        // run
        run_test();
    end
endmodule: test_top
  • my_intf.sv
//-----------------------------------------------
//@ my_intf
//@ Version : V0.1
//@ Wesley 2022.04.10
//-----------------------------------------------
`ifndef my_intf__SV
`define my_intf__SV

interface my_intf #(parameter D_WIDTH=16) (input bit clk, input bit reset_n);
    parameter setup_time = 0;
    parameter hold_time  = 0;

    // bus_if
    logic                bus_cmd_valid;
    logic                bus_op       ;
    logic [D_WIDTH-1:0]  bus_addr     ;
    logic [D_WIDTH-1:0]  bus_wr_data  ;
    logic [D_WIDTH-1:0]  bus_rd_data  ;

    // my_if
    logic [7:0]          rxd          ;
    logic                rx_dv        ;
    logic [7:0]          txd          ;
    logic                tx_en        ;

    clocking bus_cb @(posedge clk);
        default input #setup_time output #hold_time;

        output  bus_cmd_valid;
        output  bus_op       ;
        output  bus_addr     ;
        output  bus_wr_data  ;

        input   bus_rd_data  ;
    endclocking : bus_cb

    clocking mod_cb @(posedge clk);
        default input #setup_time output #hold_time;

        output  rxd  ;
        output  rx_dv;

        input   txd  ;
        input   tx_en;
    endclocking : mod_cb

    modport BUS(clocking bus_cb);
    modport MOD(clocking mod_cb);

endinterface: my_intf

`endif // my_intf__SV

  • my_base_test.sv
//-----------------------------------------------
//@ my_base_test
//@ Version : V0.1
//@ Wesley 2022.04.10
//-----------------------------------------------
`ifndef my_base_test__SV
`define my_base_test__SV

class my_callback extends CB_A;
    virtual my_intf    MY0;
    `uvm_object_utils(my_callback)

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

    virtual task drive_item(my0_driver m0_drv, my0_seq_item req);
        if(!uvm_config_db #(virtual my_intf)::get(null, "uvm_test_top*", "vif.BUS", MY0))
        begin
            `uvm_fatal(get_type_name(), "not SET : virtual my_intf")
        end

        `uvm_info(get_type_name(), $sformatf(" bus_op = %0h ", req.bus_op), UVM_DEBUG)
        `uvm_info(get_type_name(), $sformatf(" bus_addr = %0h ", req.bus_addr), UVM_DEBUG)
        `uvm_info(get_type_name(), $sformatf(" bus_wr_data = %0h ", req.bus_wr_data), UVM_DEBUG)
        `uvm_info(get_type_name(), $sformatf(" bus_rd_data = %0h ", req.bus_rd_data), UVM_DEBUG)
        
        @(posedge MY0.clk);
        MY0.bus_addr   <= req.bus_addr   ;
        @(posedge MY0.clk);
        if(req.bus_op) begin
            MY0.bus_wr_data  <= req.bus_wr_data  ;
            MY0.bus_op  <= 1'b1 ;
        end
        else begin
            req.bus_rd_data <= MY0.bus_rd_data;
            MY0.bus_op  <= 1'b0 ;
        end
        @(posedge MY0.clk);
        MY0.bus_cmd_valid <= 1;

        @(posedge MY0.clk);
        MY0.bus_addr   <= 0;
        MY0.bus_cmd_valid <= 0;
        MY0.bus_op  <= 0;
        MY0.bus_wr_data  <= 0;
    endtask

endclass

class my_base_test extends uvm_test;

    `uvm_component_utils(my_base_test)
    my_env             m_env;
    my0_agent_config   m0_agent_cfg;
    virtual my_intf    MY0;
    //my0_seq            m_seq;
    //my0_override_seq   m_seq;

    extern function new(string name = "my_base_test", uvm_component parent = null);
    extern function void build_phase(uvm_phase phase);
    extern function void connect_phase(uvm_phase phase);
    extern function void end_of_elaboration_phase(uvm_phase phase);
    extern virtual task  run_phase(uvm_phase phase);
    extern function void report_phase(uvm_phase phase);
    extern function void final_phase(uvm_phase phase);
    //extern function void init_vseq(my_vseq_base vseq);
endclass: my_base_test

function my_base_test::new(string name = "my_base_test", uvm_component parent = null);
    super.new(name, parent);
    `uvm_info(get_type_name(), "< 000 > : new ", UVM_DEBUG)
endfunction: new

function void my_base_test::build_phase(uvm_phase phase);
    super.build_phase(phase);
    `uvm_info(get_type_name(), "< 001 > : build_phase ", UVM_DEBUG)
    m_env = my_env::type_id::create("m_env", this);
    m0_agent_cfg = my0_agent_config::type_id::create("m0_agent_cfg");

    if(!uvm_config_db #(virtual my_intf)::get(this, "", "vif.BUS", m0_agent_cfg.MY0))
    begin
        `uvm_fatal(get_type_name(), "not SET : virtual my_intf")
    end

    if(!uvm_config_db #(virtual my_intf)::get(this, "", "vif.BUS", MY0))
    begin
        `uvm_fatal(get_type_name(), "not SET : virtual my_intf")
    end

    uvm_config_db #(my0_agent_config)::set(this, "m_env*", "my0_agent_config_hook", m0_agent_cfg);

    set_type_override_by_type(my0_seq::get_type(), my0_override_seq::get_type());

    //m_seq = my0_seq::type_id::create("m_seq");
    
    //sequence : method 1
    uvm_config_db #(uvm_object_wrapper)::set(this, "m_env.m0_agent.m0_seqr.main_phase", 
                                            "default_sequence", my0_seq::type_id::get());

    //uvm_config_db #(uvm_object_wrapper)::set(this, "m_env.m0_agent.m0_seqr.main_phase", 
    //                                        "default_sequence", my_seq::type_id::get());

    //// sequence : method 2
    //uvm_config_db #(uvm_sequence_base)::set(this, "m_env.m0_agent.m0_seqr.main_phase", 
    //                                        "default_sequence", m_seq);
endfunction: build_phase

function void my_base_test::connect_phase(uvm_phase phase);
   my_callback my_cb;
   my_cb = my_callback::type_id::create("my_cb");
   super.connect_phase(phase);

   //my_cb = new("my_cb");
   CB_A_pool::add(m_env.m0_agent.m0_drv, my_cb);
endfunction: connect_phase

function void my_base_test::end_of_elaboration_phase(uvm_phase phase);
    uvm_top.print_topology;
    `uvm_info(get_type_name(), "< 003 > : end_of_elaboration_phase ", UVM_DEBUG)
endfunction: end_of_elaboration_phase

task my_base_test::run_phase(uvm_phase phase);
    // sequence : method 3
    //my0_seq m_seq = my0_seq::type_id::create("m_seq");

    super.run_phase(phase);
    phase.raise_objection(this);
    `uvm_info(get_type_name(), "< 005 > : run_phase ", UVM_DEBUG)

    //init_vseq(vseq);

    // sequence : method 3
    //m_seq.start(m_env.m0_agent.m0_seqr);

    repeat(1000) begin
        @(posedge MY0.clk);
        `uvm_info(get_type_name(), $sformatf(" reset_n = %0h ", MY0.reset_n), UVM_DEBUG)
    end

    #10000ns;
    phase.get_objection().set_drain_time(this, 1000);
    phase.drop_objection(this);
endtask: run_phase

function void my_base_test::report_phase(uvm_phase phase);
    `uvm_info(get_type_name(), "< 008 > : report_phase ", UVM_DEBUG)
    `uvm_info(get_type_name(), "+-----------------------------------------------+", UVM_DEBUG)
    `uvm_info(get_type_name(), "+-           *** UVM TEST PASSED ***           -+", UVM_DEBUG)
    `uvm_info(get_type_name(), "+-----------------------------------------------+", UVM_DEBUG)

    `uvm_info(get_type_name(), "+-----------------------------------------------+", UVM_DEBUG)
    `uvm_info(get_type_name(), "+-           *** UVM TEST FAILED ***           -+", UVM_DEBUG)
    `uvm_info(get_type_name(), "+-----------------------------------------------+", UVM_DEBUG)

endfunction: report_phase

function void my_base_test::final_phase(uvm_phase phase);
    `uvm_info(get_type_name(), "< 009 > : final_phase ", UVM_DEBUG)
endfunction: final_phase

//function void my_base_test::init_vseq(my_vseq_base vseq);
//    //vseq.m0_seqr = m_env.m0_agent.m0_seqr;
//endfunction: init_vseq

`endif // my_base_test__SV

  • my_env_list.incl
//-----------------------------------------------
//@ my_env_list
//@ Version : V0.1
//@ Wesley 2022.04.10
//-----------------------------------------------
`ifndef my_env_list__SV
`define my_env_list__SV

`include "my0_agent_list.incl"
`include "my_reference.svh"
`include "my_scoreboard.svh"
`include "my_env.svh"

`endif // my_env_list__SV

  • my_env.svh
//-----------------------------------------------
//@ my_env
//@ Version : V0.1
//@ Wesley 2022.04.10
//-----------------------------------------------
`ifndef my_env__SV
`define my_env__SV

class my_env extends uvm_env;

    `uvm_component_utils(my_env)

    my0_agent          m0_agent;
    my_scoreboard      m_scb;
    my_reference       m_ref;

    //ral
    reg_env    m_reg_env;

    // Create the UVM TLM Fifo that can accept simple_packet
    uvm_tlm_analysis_fifo #(my0_seq_item)    mon2ref_fifo;
    uvm_tlm_analysis_fifo #(my0_seq_item)    ref2scb_fifo;
    
    extern function new(string name = "my_env", uvm_component parent = null);
    extern function void build_phase(uvm_phase phase);
    extern function void connect_phase(uvm_phase phase);
endclass: my_env

function my_env::new(string name = "my_env", uvm_component parent = null);
    super.new(name, parent);
    `uvm_info(get_type_name(), "< 000 > : new ", UVM_DEBUG)
endfunction: new

function void my_env::build_phase(uvm_phase phase);
    super.build_phase(phase);
    `uvm_info(get_type_name(), "< 001 > : build_phase ", UVM_DEBUG)

    //m_env_cfg = my_env_config::type_id::create("m_env_cfg");
    m0_agent = my0_agent::type_id::create("m0_agent", this);
    m_scb    = my_scoreboard::type_id::create("m_scb", this);
    m_ref    = my_reference::type_id::create("m_ref", this);

    //ral
    m_reg_env = reg_env::type_id::create("m_reg_env", this);

    // Create a FIFO with depth 2
    mon2ref_fifo = new ("mon2ref_fifo", this);
    ref2scb_fifo = new ("ref2scb_fifo", this);

endfunction: build_phase

function void my_env::connect_phase(uvm_phase phase);
    `uvm_info(get_type_name(), "< 002 > : connect_phase ", UVM_DEBUG)
    //m0_agent.ap.connect(m_scb.imp);
    m0_agent.ap.connect(mon2ref_fifo.analysis_export);
    m_ref.get_port.connect(mon2ref_fifo.blocking_get_export);
    m_ref.ap.connect(ref2scb_fifo.analysis_export);
    m_scb.get_port.connect(ref2scb_fifo.blocking_get_export);

    //ral
    m0_agent.m0_mon.ap.connect(m_reg_env.m_apb2reg_predictor.bus_in);
    m_reg_env.m_ral_model.map.set_sequencer(m0_agent.m0_seqr, m_reg_env.m_reg2apb); 
    
    //m0_agent.ap.connect(m_ref.analysis_export);
    //m_ref.analysis_export.connect(m_scb.analysis_imp);
endfunction: connect_phase

`endif // my_env__SV

  • my_env_config.svh
//-----------------------------------------------
//@ my_env_config
//@ Version : V0.1
//@ Wesley 2022.04.10
//-----------------------------------------------
`ifndef my_env_config__SV
`define my_env_config__SV

class my_env_config extends uvm_object;

    `uvm_object_utils(my_env_config);

    apb_agent_config m_apb_agent_cfg;
    my_agent_config m_tx_my_agent_cfg;
    my_agent_config m_rx_my_agent_cfg;
    modem_config m_modem_agent_cfg;

    my_reg_block rm;

    virtual interrupt_if IRQ;

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

    extern task wait_for_interrupt();
    extern function bit get_interrupt_level();
    extern task wait_for_clock(int n = 1);
    extern task wait_for_baud_rate();

endclass: my_env_config

task my_env_config::wait_for_interrupt();
    @(posedge IRQ.IRQ);
endtask: wait_for_interrupt

function bit my_env_config::get_interrupt_level();
    if(IRQ.IRQ == 1)
        return 1;
    else
        return 0;
endfunction: get_interrupt_level

task my_env_config::wait_for_clock(int n = 1);
    repeat(n)
    @(posedge IRQ.CLK);
endtask: wait_for_clock

task my_env_config::wait_for_baud_rate();
    @(posedge IRQ.baud_out);
endtask: wait_for_baud_rate

`endif // my_env_config__SV

  • my_reference.svh
//-----------------------------------------------
//@ my_reference
//@ Version : V0.1
//@ Wesley 2022.04.10
//-----------------------------------------------
`ifndef my_reference__SV
`define my_reference__SV

// Step1 : Create a new class that extends from uvm_scoreboard
class my_reference extends uvm_component;
	`uvm_component_utils (my_reference)

	// Step2a: Declare and create a TLM Analysis Port to receive data objects from other TB components
    uvm_blocking_get_port #(my0_seq_item) get_port;//exp_port;
    uvm_analysis_port #(my0_seq_item) ap;
    //uvm_analysis_export #(my0_seq_item) analysis_export;

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

	// Step2b: Instantiate the analysis port, because afterall, its a class object
	function void build_phase (uvm_phase phase);
		ap = new ("ap", this);
		get_port = new ("get_port", this);
		//analysis_export = new ("analysis_export", this);
	endfunction

	// Step3: Define other functions and tasks that operate on the data and call them
	// Remember, this is the main task that consumes simulation time in UVM
	virtual task run_phase (uvm_phase phase);
        my0_seq_item tr;

        forever begin
            get_port.get(tr);
            if( (tr.bus_addr != 0) && (tr.bus_wr_data != 0) ) begin
                ap.write(tr);
		        `uvm_info ("m_tlm_fifo get", $sformatf("tr : \n%s", tr.sprint()), UVM_DEBUG)
            end
        end
	endtask

	// Step4: [Optional] Perform any remaining comparisons or checks before end of simulation
	virtual function void check_phase (uvm_phase phase);
		//...
	endfunction
endclass

`endif // my_reference__SV

  • my_scoreboard.svh
//-----------------------------------------------
//@ my_scoreboard
//@ Version : V0.1
//@ Wesley 2022.04.10
//-----------------------------------------------
`ifndef my_scoreboard__SV
`define my_scoreboard__SV

class my_scoreboard extends uvm_scoreboard;
	`uvm_component_utils (my_scoreboard)

	// Step2a: Declare and create a TLM Analysis Port to receive data objects from other TB components
    uvm_blocking_get_port #(my0_seq_item) get_port;
    //uvm_analysis_imp_monitor #(my0_seq_item, my_scoreboard) analysis_imp;

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

	// Step2b: Instantiate the analysis port, because afterall, its a class object
	function void build_phase (uvm_phase phase);
		get_port = new ("get_port", this);
		//analysis_imp = new ("analysis_imp", this);
	endfunction

	// Step3: Define other functions and tasks that operate on the data and call them
	// Remember, this is the main task that consumes simulation time in UVM
	virtual task run_phase (uvm_phase phase);
        my0_seq_item tr;
        forever begin
            get_port.get(tr);
		    `uvm_info ("m_tlm_fifo get", $sformatf("Data received = 0x%h , 0x%h", tr.bus_addr, tr.bus_wr_data), UVM_DEBUG)
        end
	endtask

	// Step4: [Optional] Perform any remaining comparisons or checks before end of simulation
	virtual function void check_phase (uvm_phase phase);
		//...
	endfunction
endclass

`endif // my_scoreboard__SV

  • my_callbacks.svh
`ifndef CB_A__SV
`define CB_A__SV

class CB_A extends uvm_callback;
    `uvm_object_utils(CB_A)

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

    virtual task drive_item(my0_driver m0_drv, my0_seq_item req);
    endtask
endclass

typedef uvm_callbacks#(my0_driver, CB_A) CB_A_pool;

`endif //CB_A__SV

  • my0_agent_list.incl
//-----------------------------------------------
//@ my0_agent_list
//@ Version : V0.1
//@ Wesley 2022.04.10
//-----------------------------------------------
`ifndef my0_agent_list__SV
`define my0_agent_list__SV

`include "uart_reg_pkg.sv"

`include "my0_seq_item.svh"
`include "my0_agent_config.svh"
`include "my0_driver.svh"
`include "my0_monitor.svh"
`include "my0_sequencer.svh"

`include "reg_env.sv"

`include "my0_agent.svh"

`endif // my0_agent_list__SV

  • my0_agent.svh
//-----------------------------------------------
//@ my0_agent
//@ Version : V0.1
//@ Wesley 2022.04.10
//-----------------------------------------------
`ifndef my0_agent__SV
`define my0_agent__SV

class my0_agent extends uvm_agent;

    `uvm_component_utils(my0_agent)

    my0_agent_config  m0_agent_cfg;
    
    my0_driver        m0_drv;
    my0_monitor       m0_mon;
    my0_sequencer     m0_seqr;

    uvm_analysis_port #(my0_seq_item) ap;
    
    extern function new(string name = "my0_agent", uvm_component parent = null);
    extern function void build_phase(uvm_phase phase);
    extern function void connect_phase(uvm_phase phase);
endclass: my0_agent

function my0_agent::new(string name = "my0_agent", uvm_component parent = null);
    super.new(name, parent);
    `uvm_info(get_type_name(), "< 000 > : new ", UVM_DEBUG)
endfunction: new

function void my0_agent::build_phase(uvm_phase phase);
    super.build_phase(phase);
    `uvm_info(get_type_name(), "< 001 > : build_phase ", UVM_DEBUG)

    if(!uvm_config_db #(my0_agent_config)::get(this, "", "my0_agent_config_hook", m0_agent_cfg))
    begin
        `uvm_fatal(get_type_name(), "not SET : my0_agent_config")
    end
    else begin
        `uvm_info(get_type_name(),$sformatf(" object structure:\n%s", m0_agent_cfg.sprint()),UVM_DEBUG)
    end

    ap = new("ap", this);

    if(m0_agent_cfg.active == UVM_ACTIVE) begin
        m0_drv  = my0_driver::type_id::create("m0_drv", this);
        m0_seqr = my0_sequencer::type_id::create("m0_seqr", this);
    end
    if(m0_agent_cfg.has_functional_coverage) begin
        //m_fcov_monitor = apb_coverage_monitor::type_id::create("m_fcov_monitor", this);
    end
    m0_mon  = my0_monitor::type_id::create("m0_mon", this);
endfunction: build_phase

function void my0_agent::connect_phase(uvm_phase phase);
    `uvm_info(get_type_name(), "< 002 > : connect_phase ", UVM_DEBUG)

    // connect : test_top <--> m0_drv
    if(m0_agent_cfg.active == UVM_ACTIVE) begin
        m0_drv.seq_item_port.connect(m0_seqr.seq_item_export);
        m0_drv.MY0 = m0_agent_cfg.MY0;
    end
    m0_mon.ap.connect(ap);
    m0_mon.MY0 = m0_agent_cfg.MY0;

endfunction: connect_phase

`endif // my0_agent__SV

  • my0_agent_config.svh
//-----------------------------------------------
//@ my0_agent_config
//@ Version : V0.1
//@ Wesley 2022.04.10
//-----------------------------------------------
`ifndef my0_agent_config__SV
`define my0_agent_config__SV

class my0_agent_config extends uvm_object;

    // Virtual Interface
    virtual my_intf MY0;

    // Is the agent active or passive
    uvm_active_passive_enum active = UVM_ACTIVE;

    // Include the APB functional coverage monitor
    bit has_functional_coverage = 0;
    // Include the APB RAM based scoreboard
    bit has_scoreboard = 0;
    //
    // Address decode for the select lines:
    int no_select_lines = 1;
    int apb_index = 0; // Which PSEL is the monitor connected to
    logic[31:0] start_address[];
    logic[31:0] range[];

   `uvm_object_utils_begin(my0_agent_config)
        `uvm_field_enum(uvm_active_passive_enum, active, UVM_ALL_ON) 
        `uvm_field_int(has_functional_coverage, UVM_DEFAULT | UVM_HEX)
        `uvm_field_int(has_scoreboard, UVM_DEFAULT | UVM_HEX)
        `uvm_field_int(no_select_lines, UVM_DEFAULT | UVM_HEX)
        `uvm_field_int(apb_index, UVM_DEFAULT | UVM_HEX)
        `uvm_field_array_int(start_address, UVM_ALL_ON)
        `uvm_field_array_int(range, UVM_ALL_ON)
   `uvm_object_utils_end
    
    function new(string name = "my0_agent_config");
        super.new(name);
    endfunction

endclass: my0_agent_config

`endif // my0_agent_config__SV

  • my0_seq_item.svh
//-----------------------------------------------
//@ my0_seq_item
//@ Version : V0.1
//@ Wesley 2022.04.10
//-----------------------------------------------
`ifndef my0_seq_item__SV
`define my0_seq_item__SV

class my0_seq_item extends uvm_sequence_item;
    //------------------------------------------
    // Data Members (Outputs rand, inputs non-rand)
    //------------------------------------------
    // bus_if
    rand logic           bus_cmd_valid;
    rand logic           bus_op       ;
    rand logic [16-1:0]  bus_addr     ;
    rand logic [16-1:0]  bus_wr_data  ;
         logic [16-1:0]  bus_rd_data  ;

    // my_if
    rand logic [7:0]     rxd   ;
    rand logic           rx_dv ;
         logic [7:0]     txd   ;
         logic           tx_en ;

    // UVM Factory Registration Macro
    `uvm_object_utils_begin(my0_seq_item)
    `uvm_field_int( bus_cmd_valid, UVM_ALL_ON )
    `uvm_field_int( bus_op       , UVM_ALL_ON )
    `uvm_field_int( bus_addr     , UVM_ALL_ON )
    `uvm_field_int( bus_wr_data  , UVM_ALL_ON )
    `uvm_field_int( bus_rd_data  , UVM_ALL_ON )
    `uvm_field_int( rxd          , UVM_ALL_ON )
    `uvm_field_int( rx_dv        , UVM_ALL_ON )
    `uvm_field_int( txd          , UVM_ALL_ON )
    `uvm_field_int( tx_en        , UVM_ALL_ON )
    `uvm_object_utils_end

    //------------------------------------------
    // Constraints
    //------------------------------------------
    constraint addr_alignment {
        bus_addr   >= 32'h4000;
        bus_addr%2 == 0;
    }

    //------------------------------------------
    // Methods
    //------------------------------------------

    // Standard UVM Methods:
    function new(string name = "my0_seq_item");
        super.new(name);
    endfunction

endclass:my0_seq_item

`endif // my0_seq_item__SV

  • my0_driver.svh
//-----------------------------------------------
//@ my0_driver
//@ Version : V0.1
//@ Wesley 2022.04.10
//-----------------------------------------------
`ifndef my0_driver__SV
`define my0_driver__SV

//callback
typedef class CB_A; 

class my0_driver extends uvm_driver#(my0_seq_item);
    `uvm_component_utils(my0_driver)
    //callback
    `uvm_register_cb(my0_driver, CB_A)

    virtual my_intf MY0;
    my0_seq_item rsp;
    extern function new(string name = "my0_driver", uvm_component parent = null);
    extern function void build_phase(uvm_phase phase);
    extern function void connect_phase(uvm_phase phase);
    extern task          run_phase(uvm_phase phase);
    //extern virtual task  drive_item(my0_seq_item req);

endclass: my0_driver

function my0_driver::new(string name = "my0_driver", uvm_component parent = null);
    super.new(name, parent);
    `uvm_info(get_type_name(), "< 000 > : new ", UVM_DEBUG)
endfunction: new

function void my0_driver::build_phase(uvm_phase phase);
    `uvm_info(get_type_name(), "< 001 > : build_phase ", UVM_DEBUG)
endfunction: build_phase

function void my0_driver::connect_phase(uvm_phase phase);
    `uvm_info(get_type_name(), "< 002 > : connect_phase ", UVM_DEBUG)
endfunction: connect_phase

task my0_driver::run_phase(uvm_phase phase);
    `uvm_info(get_type_name(), "< 005 > : run_phase ", UVM_DEBUG)
    super.run_phase(phase);
	// Loop the following steps
    MY0.bus_addr   <= 0;
    MY0.bus_cmd_valid <= 0;
    MY0.bus_op  <= 0;
    MY0.bus_wr_data  <= 0;

    while(!MY0.reset_n)
        @(posedge MY0.clk);
    while(1) begin
        `uvm_info(get_type_name(), $sformatf(" 1. Get next item from the sequencer !!!"), UVM_DEBUG)
        seq_item_port.get_next_item(req);
        `uvm_info(get_type_name(), $sformatf(" 2-1. drive item into DUT interface !!! \n%s\n", req.sprint()), UVM_DEBUG)
        
        //callback
        `uvm_do_callbacks(my0_driver, CB_A, drive_item(this, req))

        //drive_item(req);
        `uvm_info(get_type_name(), $sformatf(" 2-2. put_response !!!"), UVM_DEBUG)
        rsp = new("rsp");
        $cast(rsp, req.clone());
        rsp.set_id_info(req);
        seq_item_port.put_response(rsp);
        `uvm_info(get_type_name(), $sformatf(" 3. Finish driving transaction !!!"), UVM_DEBUG)
        seq_item_port.item_done();
    end
endtask: run_phase

//task my0_driver::drive_item(my0_seq_item req);
//    `uvm_info(get_type_name(), $sformatf(" bus_op = %0h ", req.bus_op), UVM_DEBUG)
//    `uvm_info(get_type_name(), $sformatf(" bus_addr = %0h ", req.bus_addr), UVM_DEBUG)
//    `uvm_info(get_type_name(), $sformatf(" bus_wr_data = %0h ", req.bus_wr_data), UVM_DEBUG)
//    `uvm_info(get_type_name(), $sformatf(" bus_rd_data = %0h ", req.bus_rd_data), UVM_DEBUG)
//    
//    @(posedge MY0.clk);
//    MY0.bus_addr   <= req.bus_addr   ;
//    @(posedge MY0.clk);
//    if(req.bus_op) begin
//        MY0.bus_wr_data  <= req.bus_wr_data  ;
//        MY0.bus_op  <= 1'b1 ;
//    end
//    else begin
//        req.bus_rd_data <= MY0.bus_rd_data;
//        MY0.bus_op  <= 1'b0 ;
//    end
//    @(posedge MY0.clk);
//    MY0.bus_cmd_valid <= 1;
//
//    @(posedge MY0.clk);
//    MY0.bus_addr   <= 0;
//    MY0.bus_cmd_valid <= 0;
//    MY0.bus_op  <= 0;
//    MY0.bus_wr_data  <= 0;
//
//endtask: drive_item

`endif // my0_driver__SV

  • my0_monitor.svh
//-----------------------------------------------
//@ my0_monitor
//@ Version : V0.1
//@ Wesley 2022.04.10
//-----------------------------------------------
`ifndef my0_monitor__SV
`define my0_monitor__SV

class my0_monitor extends uvm_monitor;

    `uvm_component_utils(my0_monitor)

    virtual my_intf MY0;
    uvm_analysis_port #(my0_seq_item) ap;
    my0_seq_item pkg;
    
    extern function new(string name = "my0_monitor", uvm_component parent = null);
    extern function void build_phase(uvm_phase phase);
    extern function void connect_phase(uvm_phase phase);
    extern task          run_phase(uvm_phase phase);
endclass: my0_monitor

function my0_monitor::new(string name = "my0_monitor", uvm_component parent = null);
    super.new(name, parent);
    `uvm_info(get_type_name(), "< 000 > : new ", UVM_DEBUG)
endfunction: new

function void my0_monitor::build_phase(uvm_phase phase);
    `uvm_info(get_type_name(), "< 001 > : build_phase ", UVM_DEBUG)
    ap = new("ap", this);
endfunction: build_phase

function void my0_monitor::connect_phase(uvm_phase phase);
    `uvm_info(get_type_name(), "< 002 > : connect_phase ", UVM_DEBUG)
endfunction: connect_phase

task my0_monitor::run_phase(uvm_phase phase);
    `uvm_info(get_type_name(), "< 005 > : run_phase ", UVM_DEBUG)
    forever begin
        @(posedge MY0.clk);
        pkg = my0_seq_item::type_id::create("pkg");
        pkg.bus_addr   = MY0.bus_addr   ;
        pkg.bus_wr_data  = MY0.bus_wr_data  ;
        pkg.bus_op  = MY0.bus_op  ;
        pkg.bus_cmd_valid = MY0.bus_cmd_valid ;
        pkg.bus_rd_data  = MY0.bus_rd_data  ;

        ap.write(pkg);
    end
endtask: run_phase

`endif // my0_monitor__SV

  • my0_sequencer.svh
//-----------------------------------------------
//@ my0_sequencer
//@ Version : V0.1
//@ Wesley 2022.04.10
//-----------------------------------------------
`ifndef my0_sequencer__SV
`define my0_sequencer__SV

class my0_sequencer extends uvm_sequencer #(my0_seq_item);

    `uvm_component_utils(my0_sequencer)
    
    function new(string name = "my0_sequencer", uvm_component parent = null);
        super.new(name, parent);
        `uvm_info(get_type_name(), "< 000 > : new ", UVM_DEBUG)
    endfunction: new

endclass: my0_sequencer

`endif // my0_sequencer__SV


  • reg_env.sv
class reg2apb_adapter extends uvm_reg_adapter;
    `uvm_object_utils (reg2apb_adapter)

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

    virtual function uvm_sequence_item reg2bus (const ref uvm_reg_bus_op rw);
        my0_seq_item pkt = my0_seq_item::type_id::create ("pkt");
        pkt.bus_op = (rw.kind == UVM_WRITE) ? 1: 0;
        pkt.bus_addr  = rw.addr;
        pkt.bus_wr_data  = rw.data;
        `uvm_info ("adapter", $sformatf ("reg2bus addr=0x%0h data=0x%0h kind=%s", pkt.bus_addr, pkt.bus_wr_data, rw.kind.name), UVM_DEBUG)
        return pkt;
    endfunction

    virtual function void bus2reg (uvm_sequence_item bus_item, ref uvm_reg_bus_op rw);
        my0_seq_item pkt;
        if (! $cast (pkt, bus_item)) begin
            `uvm_fatal ("reg2apb_adapter", "Failed to cast bus_item to pkt")
        end

        rw.kind = pkt.bus_op ? UVM_WRITE : UVM_READ;
        rw.addr = pkt.bus_addr;
        rw.data = pkt.bus_rd_data;
        `uvm_info ("adapter", $sformatf("bus2reg : addr=0x%0h data=0x%0h kind=%s status=%s", rw.addr, rw.data, rw.kind.name(), rw.status.name()), UVM_DEBUG)
    endfunction
endclass

// Register environment class puts together the model, adapter and the predictor
class reg_env extends uvm_env;
    `uvm_component_utils (reg_env)
    function new (string name="reg_env", uvm_component parent);
        super.new (name, parent);
    endfunction

    uart_reg_block                m_ral_model;         // Register Model
    reg2apb_adapter                m_reg2apb;           // Convert Reg Tx <-> Bus-type packets
    uvm_reg_predictor #(my0_seq_item)   m_apb2reg_predictor; // Map APB tx to register in model

    virtual function void build_phase (uvm_phase phase);
        super.build_phase (phase);
        m_ral_model          = uart_reg_block::type_id::create ("m_ral_model", this);
        m_reg2apb            = reg2apb_adapter :: type_id :: create ("m_reg2apb");
        m_apb2reg_predictor  = uvm_reg_predictor #(my0_seq_item) :: type_id :: create ("m_apb2reg_predictor", this);

        m_ral_model.build ();
        m_ral_model.lock_model ();
        m_ral_model.reset ();
        uvm_config_db #(uart_reg_block)::set (null, "uvm_test_top", "m_ral_model", m_ral_model);
    endfunction

    virtual function void connect_phase (uvm_phase phase);
        super.connect_phase (phase);
        m_apb2reg_predictor.map       = m_ral_model.map;
        m_apb2reg_predictor.adapter   = m_reg2apb;
        m_ral_model.default_map.set_auto_predict(1);
    endfunction
endclass

  • uart_reg_pkg.sv
//-----------------------------------------------
//   Copyright 2012 Mentor Graphics Corporation
//   All Rights Reserved Worldwide
//
//   Licensed under the Apache License, Version 2.0 (the
//   "License"); you may not use this file except in
//   compliance with the License.  You may obtain a copy of
//   the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in
//   writing, software distributed under the License is
//   distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
//   CONDITIONS OF ANY KIND, either express or implied.  See
//   the License for the specific language governing
//   permissions and limitations under the License.
//-----------------------------------------------

class txd_reg extends uvm_reg;
  `uvm_object_utils(txd_reg)

  rand uvm_reg_field data;

  function new(string name = "txd_reg");
    super.new(name, 8, UVM_NO_COVERAGE);
  endfunction

  function void build();
    data = uvm_reg_field::type_id::create("data");
    data.configure(this, 8, 0, "WO", 0, 8'h0, 0, 1, 0);
  endfunction: build
endclass: txd_reg

class rxd_reg extends uvm_reg;
  `uvm_object_utils(rxd_reg)

  uvm_reg_field data;

  function new(string name = "rxd_reg");
    super.new(name, 8, UVM_NO_COVERAGE);
  endfunction

  function void build();
    data = uvm_reg_field::type_id::create("data");
    data.configure(this, 8, 0, "RO", 0, 8'h0, 0, 0, 0);
  endfunction: build
endclass: rxd_reg

class ier_reg extends uvm_reg;
  `uvm_object_utils(ier_reg)

  rand uvm_reg_field RDI;
  rand uvm_reg_field TXE;
  rand uvm_reg_field RXS;
  rand uvm_reg_field MSI;

  function new(string name = "ier_reg");
    super.new(name, 4, UVM_NO_COVERAGE);
  endfunction

  function void build();
    RDI = uvm_reg_field::type_id::create("RDI");
    RDI.configure(this, 1, 0, "RW", 0, 0, 1, 1, 0);
    TXE = uvm_reg_field::type_id::create("TXE");
    TXE.configure(this, 1, 1, "RW", 0, 0, 1, 1, 0);
    RXS = uvm_reg_field::type_id::create("RXS");
    RXS.configure(this, 1, 2, "RW", 0, 0, 1, 1, 0);
    MSI = uvm_reg_field::type_id::create("MSI");
    MSI.configure(this, 1, 3, "RW", 0, 0, 1, 1, 0);
  endfunction: build

endclass: ier_reg

class fcr_reg extends uvm_reg;
  `uvm_object_utils(fcr_reg)

  rand uvm_reg_field unused;
  rand uvm_reg_field RFITL;

  function new(string name = "fcr_reg");
    super.new(name, 8, UVM_NO_COVERAGE);
  endfunction

  function void build();
    unused = uvm_reg_field::type_id::create("unused");
    unused.configure(this, 6, 0, "WO", 0, 0, 1, 0, 0);
    RFITL = uvm_reg_field::type_id::create("RFITL");
    RFITL.configure(this, 2, 6, "WO", 0, 2'b11, 1, 1, 0);
  endfunction: build

endclass: fcr_reg

class iid_reg extends uvm_reg;
  `uvm_object_utils(iid_reg)

  uvm_reg_field ID;
  uvm_reg_field unused;

  function new(string name = "iid_reg");
    super.new(name, 8, UVM_NO_COVERAGE);
  endfunction

  function void build();
    ID = uvm_reg_field::type_id::create("ID");
    ID.configure(this, 4, 0, "RO", 1, 4'h1, 1, 0, 0);
    unused = uvm_reg_field::type_id::create("unused");
    unused.configure(this, 4, 4, "RO", 1, 4'hc, 1, 0, 0);
  endfunction: build

endclass: iid_reg

class lcr_reg extends uvm_reg;
  `uvm_object_utils(lcr_reg)

  rand uvm_reg_field WL;
  rand uvm_reg_field STP;
  rand uvm_reg_field PE;
  rand uvm_reg_field EP;
  rand uvm_reg_field SP;
  rand uvm_reg_field BRK;
  rand uvm_reg_field DLAB;

  function new(string name = "lcr_reg");
    super.new(name, 8, UVM_NO_COVERAGE);
  endfunction

  function void build();
    WL = uvm_reg_field::type_id::create("WL");
    WL.configure(this, 2, 0, "RW", 0, 2'b11, 1, 1, 0);
    STP = uvm_reg_field::type_id::create("STP");
    STP.configure(this, 1, 2, "RW", 0, 1'b0, 1, 1, 0);
    PE = uvm_reg_field::type_id::create("PE");
    PE.configure(this, 1, 3, "RW", 0, 1'b0, 1, 1, 0);
    EP = uvm_reg_field::type_id::create("EP");
    EP.configure(this, 1, 4, "RW", 0, 1'b0, 1, 1, 0);
    SP = uvm_reg_field::type_id::create("SP");
    SP.configure(this, 1, 5, "RW", 0, 1'b0, 1, 1, 0);
    BRK = uvm_reg_field::type_id::create("BRK");
    BRK.configure(this, 1, 6, "RW", 0, 1'b0, 1, 1, 0);
    DLAB = uvm_reg_field::type_id::create("DLAB");
    DLAB.configure(this, 1, 7, "RW", 0, 1'b0, 1, 1, 0);
  endfunction

endclass: lcr_reg

class mcr_reg extends uvm_reg;
  `uvm_object_utils(mcr_reg)

  rand uvm_reg_field DTR;
  rand uvm_reg_field RTS;
  rand uvm_reg_field OUT1;
  rand uvm_reg_field OUT2;
  rand uvm_reg_field LBACK;

  function new(string name = "mcr_reg");
    super.new(name, 5, UVM_NO_COVERAGE);
  endfunction

  function void build();
    DTR = uvm_reg_field::type_id::create("DTR");
    DTR.configure(this, 1, 0, "WO", 0, 1'b0, 1, 1, 0);
    RTS = uvm_reg_field::type_id::create("RTS");
    RTS.configure(this, 1, 1, "WO", 0, 1'b0, 1, 1, 0);
    OUT1 = uvm_reg_field::type_id::create("OUT1");
    OUT1.configure(this, 1, 2, "WO", 0, 1'b0, 1, 1, 0);
    OUT2 = uvm_reg_field::type_id::create("OUT2");
    OUT2.configure(this, 1, 3, "WO", 0, 1'b0, 1, 1, 0);
    LBACK = uvm_reg_field::type_id::create("LBACK");
    LBACK.configure(this, 1, 4, "WO", 0, 1'b0, 1, 1, 0);
  endfunction: build

endclass: mcr_reg

class lsr_reg extends uvm_reg;
  `uvm_object_utils(lsr_reg)

  uvm_reg_field DR;
  uvm_reg_field OE;
  uvm_reg_field PE;
  uvm_reg_field FE;
  uvm_reg_field BI;
  uvm_reg_field TFE;
  uvm_reg_field TXE;
  uvm_reg_field RFE;

  function new(string name = "lsr_reg");
    super.new(name, 8, UVM_NO_COVERAGE);
  endfunction

  function void build();
    DR = uvm_reg_field::type_id::create("DR");
    DR.configure(this, 1, 0, "RO", 0, 1'b0, 1, 0, 0);
    OE = uvm_reg_field::type_id::create("OE");
    OE.configure(this, 1, 1, "RC", 0, 1'b0, 1, 0, 0);
    PE = uvm_reg_field::type_id::create("PE");
    PE.configure(this, 1, 2, "RC", 0, 1'b0, 1, 0, 0);
    FE = uvm_reg_field::type_id::create("FE");
    FE.configure(this, 1, 3, "RC", 0, 1'b0, 1, 0, 0);
    BI = uvm_reg_field::type_id::create("BI");
    BI.configure(this, 1, 4, "RC", 0, 1'b0, 1, 0, 0);
    TFE = uvm_reg_field::type_id::create("TFE");
    TFE.configure(this, 1, 5, "RO", 0, 1'b0, 1, 0, 0);
    TXE = uvm_reg_field::type_id::create("TXE");
    TXE.configure(this, 1, 6, "RO", 0, 1'b0, 1, 0, 0);
    RFE = uvm_reg_field::type_id::create("RFE");
    RFE.configure(this, 1, 7, "RC", 0, 1'b0, 1, 0, 0);
  endfunction: build

endclass: lsr_reg

class msr_reg extends uvm_reg;
  `uvm_object_utils(msr_reg)

  uvm_reg_field DCTS;
  uvm_reg_field DDSR;
  uvm_reg_field TERI;
  uvm_reg_field DDCD;
  uvm_reg_field CTS;
  uvm_reg_field DSR;
  uvm_reg_field RI;
  uvm_reg_field DCD;

  function new(string name = "msr_reg");
    super.new(name, 8, UVM_NO_COVERAGE);
  endfunction

  function void build();
    DCTS = uvm_reg_field::type_id::create("DCTS");
    DCTS.configure(this, 1, 0, "RC", 0, 1'b0, 1, 0, 0);
    DDSR = uvm_reg_field::type_id::create("DDSR");
    DDSR.configure(this, 1, 1, "RC", 0, 1'b0, 1, 0, 0);
    TERI = uvm_reg_field::type_id::create("TERI");
    TERI.configure(this, 1, 2, "RC", 0, 1'b0, 1, 0, 0);
    DDCD = uvm_reg_field::type_id::create("DDCD");
    DDCD.configure(this, 1, 3, "RC", 0, 1'b0, 1, 0, 0);
    CTS = uvm_reg_field::type_id::create("CTS");
    CTS.configure(this, 1, 4, "RO", 0, 1'b0, 1, 0, 0);
    DSR = uvm_reg_field::type_id::create("DSR");
    DSR.configure(this, 1, 5, "RO", 0, 1'b0, 1, 0, 0);
    RI = uvm_reg_field::type_id::create("RI");
    RI.configure(this, 1, 6, "RO", 0, 1'b0, 1, 0, 0);
    DCD = uvm_reg_field::type_id::create("DCD");
    DCD.configure(this, 1, 7, "RO", 0, 1'b0, 1, 0, 0);
  endfunction: build

endclass: msr_reg

class div_reg extends uvm_reg;
  `uvm_object_utils(div_reg)

  rand uvm_reg_field DIV;

  function new(string name = "div_reg");
    super.new(name, 8, UVM_NO_COVERAGE);
  endfunction

  function void build();
    DIV = uvm_reg_field::type_id::create("DIV");
    DIV.configure(this, 8, 0, "RW", 0, 8'h0, 1, 1, 0);
  endfunction: build

endclass: div_reg

class uart_reg_block extends uvm_reg_block;
  `uvm_object_utils(uart_reg_block)

  rand txd_reg TXD;
  rand rxd_reg RXD;
  rand ier_reg IER;
  iid_reg IID;
  rand fcr_reg FCR;
  rand lcr_reg LCR;
  rand mcr_reg MCR;
  lsr_reg LSR;
  msr_reg MSR;
  rand div_reg DIV1;
  rand div_reg DIV2;

  uvm_reg_map map;

  function new(string name = "uart_reg_block");
    super.new(name, UVM_NO_COVERAGE);
  endfunction

  function void build();
    TXD = txd_reg::type_id::create("TXD");
    TXD.build();
    TXD.configure(this);
    RXD = rxd_reg::type_id::create("RXD");
    RXD.build();
    RXD.configure(this);
    IER = ier_reg::type_id::create("IER");
    IER.build();
    IER.configure(this);
    IID = iid_reg::type_id::create("IID");
    IID.build();
    IID.configure(this);
    FCR = fcr_reg::type_id::create("FCR");
    FCR.build();
    FCR.configure(this);
    LCR = lcr_reg::type_id::create("LCR");
    LCR.build();
    LCR.configure(this);
    MCR = mcr_reg::type_id::create("MCR");
    MCR.build();
    MCR.configure(this);
    LSR = lsr_reg::type_id::create("LSR");
    LSR.build();
    LSR.configure(this);
    MSR = msr_reg::type_id::create("MSR");
    MSR.build();
    MSR.configure(this);
    DIV1 = div_reg::type_id::create("DIV1");
    DIV1.build();
    DIV1.configure(this);
    DIV2 = div_reg::type_id::create("DIV2");
    DIV2.build();
    DIV2.configure(this);

    map = create_map("map", 'h0, 4, UVM_LITTLE_ENDIAN);

    map.add_reg(TXD, 32'h0, "WO");
    map.add_reg(RXD, 32'h0, "RO");
    map.add_reg(IER, 32'h4, "RW");
    map.add_reg(IID, 32'h8, "RO");
    map.add_reg(FCR, 32'h8, "WO");
    map.add_reg(LCR, 32'hc, "RW");
    map.add_reg(MCR, 32'h10, "RW");
    map.add_reg(LSR, 32'h14, "RO");
    map.add_reg(MSR, 32'h18, "RO");
    map.add_reg(DIV1, 32'h1c, "RW");
    map.add_reg(DIV2, 32'h20, "RW");

    lock_model();
  endfunction

endclass: uart_reg_block


  • my0_seq.svh
//-----------------------------------------------
//@ my0_seq
//@ Version : V0.1
//@ Wesley 2022.04.10
//-----------------------------------------------
`ifndef my0_seq__SV
`define my0_seq__SV

class my0_seq extends uvm_sequence #(my0_seq_item);

    `uvm_object_utils(my0_seq)
    `uvm_declare_p_sequencer (my0_sequencer)

    rand int no_rx_chars;

    rand bit[7:0] lcr;
    rand bit[15:0] baud_divisor;
    rand bit no_errors;

    rand bit[3:0] IER;
    uvm_status_e status;
    uart_reg_block rm;
    virtual my_intf MY0;
    my0_seq_item req;

    function new(string name = "my0_seq");
        super.new(name);
        //UVM1.2
        //set_automatic_phase_objection(1);
    endfunction

    virtual task pre_body;
        uvm_phase phase;
        super.pre_body();
        `ifdef UVM_VERSION_1_2
            phase = get_starting_phase();
        `else
            phase = starting_phase;
        `endif
        if(phase != null) phase.raise_objection(this);
        `uvm_info(get_type_name(), "< SEQ-1 > : pre_body ", UVM_DEBUG)
    endtask: pre_body

    virtual task post_body;
        uvm_phase phase;
        super.post_body();
        `ifdef UVM_VERSION_1_2
            phase = get_starting_phase();
        `else
            phase = starting_phase;
        `endif
        if(phase != null) phase.drop_objection(this);
        `uvm_info(get_type_name(), "< SEQ-3 > : post_body ", UVM_DEBUG)
    endtask: post_body

    virtual task body;
        bit[31:0] data;

        if(!uvm_config_db #(virtual my_intf)::get(null, "uvm_test_top*", "vif.BUS", MY0))
        begin
            `uvm_fatal(get_type_name(), "not SET : virtual my_intf")
        end

        //if(!uvm_config_db #(uart_reg_block)::get(null, "uvm_test_top", "m_ral_model", rm))
        //begin
        //    `uvm_fatal(get_type_name(), "not SET : m_ral_model")
        //end


        //@(posedge MY0.clk);
        //IER = 4'h8;
        //rm.IER.write(status, {'0, IER}, UVM_FRONTDOOR);

        //@(posedge MY0.clk);
        //assert(this.randomize() with {data[4] == 1;});
        //rm.MCR.write(status, data, UVM_FRONTDOOR);

        //@(posedge MY0.clk);

        //rm.MCR.write(status, 32'ha, UVM_FRONTDOOR);
        //rm.MCR.write(status, 32'h4, UVM_FRONTDOOR);
    
        //repeat(100) begin
        //    @(posedge MY0.clk);
        //    req = my0_seq_item::type_id::create("req"); // 1. create item
        //    start_item(req); // 2. start item to sequencer
        //    assert(req.randomize() with {req.bus_wr_data >= 100;}); // 3. randomize()
        //    finish_item(req); // 4. send item to driver
        //    `uvm_info(get_type_name(), $sformatf("< SEQ-2-1 > : %h, %h", req.bus_addr, req.bus_wr_data), UVM_DEBUG)
        //    get_response(rsp);
        //    //`uvm_info(get_type_name(), $sformatf("rsp \n%s\n", rsp.sprint()), UVM_DEBUG)
        //    rsp.print();
        //end

        repeat(100) begin
            @(posedge MY0.clk);
            req = new("req"); // 1. create item
            `uvm_do_with(req, {req.bus_addr < 32'h4FFFFFFF; req.bus_wr_data != 32'h4444FFFF;})
            `uvm_info(get_type_name(), $sformatf("< SEQ-2-2 > : %h, %h", req.bus_addr, req.bus_wr_data), UVM_DEBUG)
            get_response(rsp);
            `uvm_info(get_type_name(), $sformatf("rsp \n%s\n", rsp.sprint()), UVM_DEBUG)
        end
        `uvm_info(get_type_name(), "< SEQ-2 > : body ", UVM_DEBUG)
    endtask: body

endclass: my0_seq

`endif // my0_seq__SV

  • my0_override_seq.svh
//-----------------------------------------------
//@ my0_override_seq
//@ Version : V0.1
//@ Wesley 2022.04.10
//-----------------------------------------------
`ifndef my0_override_seq__SV
`define my0_override_seq__SV

class my0_override_seq extends my0_seq;

    `uvm_object_utils(my0_override_seq)
    `uvm_declare_p_sequencer (my0_sequencer)
    virtual my_intf MY0;

    function new(string name = "my0_override_seq");
        super.new(name);
        //UVM1.2
        //set_automatic_phase_objection(1);
    endfunction

    virtual task pre_body;
        uvm_phase phase;
        super.pre_body();
        `ifdef UVM_VERSION_1_2
            phase = get_starting_phase();
        `else
            phase = starting_phase;
        `endif
        if(phase != null) phase.raise_objection(this);
        `uvm_info(get_type_name(), "< SEQ-1 > : pre_body ", UVM_DEBUG)
    endtask: pre_body

    virtual task post_body;
        uvm_phase phase;
        super.post_body();
        `ifdef UVM_VERSION_1_2
            phase = get_starting_phase();
        `else
            phase = starting_phase;
        `endif
        if(phase != null) phase.drop_objection(this);
        `uvm_info(get_type_name(), "< SEQ-3 > : post_body ", UVM_DEBUG)
    endtask: post_body

    virtual task body;
        bit[31:0] data;

        if(!uvm_config_db #(virtual my_intf)::get(null, "uvm_test_top*", "vif.BUS", MY0))
        begin
            `uvm_fatal(get_type_name(), "not SET : virtual my_intf")
        end

        repeat(50) begin
            @(posedge MY0.clk);
            req = new("req"); // 1. create item
            `uvm_do_with(req, {req.bus_addr == 32'h00000004; req.bus_wr_data == 32'h0000000F;})
            `uvm_info(get_type_name(), $sformatf("< SEQ-2-2 > : %h, %h", req.bus_addr, req.bus_wr_data), UVM_DEBUG)
            get_response(rsp);
            `uvm_info(get_type_name(), $sformatf("rsp \n%s\n", rsp.sprint()), UVM_DEBUG)
        end
        `uvm_info(get_type_name(), "< SEQ-2 > : body ", UVM_DEBUG)
    endtask: body

endclass: my0_override_seq

  • wave.tcl
call {$fsdbDumpvars(0, test_top, "+all")}
call {$fsdbDumpSVA (0, test_top)}
call {$fsdbDumpMDA (0, test_top)}
run
  • filelist.f
+incdir+../tb
+incdir+../tb/env
+incdir+../tb/env/agents
+incdir+../tb/env/agents/apb_agent
+incdir+../tb/env/agents/my0_agent
+incdir+../tb/env/protocol_monitor
+incdir+../tb/register_model
+incdir+../tc
+incdir+../tc/virtual_sequences
+incdir+../tc/sequences
+incdir+../tc/tests

-F ../rtl/filelist.f
../tb/my_test_pkg.sv
../tb/test_top.sv

posted @ 2022-07-17 19:22  Thisway2014  阅读(624)  评论(0编辑  收藏  举报