跳转至

输入查询内容

    本页内容

    Phase、配置、工厂、Sequence、Callback、TLM 与 RAL 基础对照

    环境:VCS W-2024.09-SP2-8。1.2 使用 uvm-1.2,2.0 使用 uvm-ieee-2020-2.0

    实验检查观察值是否符合预期;成功复现问题不代表问题已修复。

    结果对比

    观察内容 UVM 1.2 UVM 2.0
    寄存器写状态(0=成功,1=失败) reg_write_status 0 0
    寄存器读状态(0=成功,1=失败) reg_read_status 0 0
    寄存器读回数据 reg_read_data 0123456789abcdef 0123456789abcdef
    寄存器模型镜像值 reg_mirror_data 0123456789abcdef 0123456789abcdef
    objection 总数 objection_total 1 1
    phase 执行顺序 phase_order build>connect>run>extract>report build>connect>run>extract>report
    实际取得的配置值 config_value 42 42
    工厂 override 是否生效(1=是) factory_override 1 1
    sequence 保持预期 parent(1=是) sequence_parent 1 1
    按 phase 配置的默认 sequence 启动次数 phase_default_sequences 2 2
    旧字符串配置的默认 sequence 启动次数 legacy_default_sequence 1 0
    回调调用次数 callback_calls 5 5
    总线传输次数 bus_transfers 5 5

    运行命令

    目录与环境准备;从解包根目录执行:

    uv run tools/run_uvm_review.py --case feature_matrix --variants 12,20
    

    最小源码

    feature_matrix.sv

    feature_matrix.sv
    `timescale 1ns/1ps
    `include "uvm_macros.svh"
    import uvm_pkg::*;
    
    class bus_item extends uvm_sequence_item;
      `uvm_object_utils(bus_item)
      bit write;
      int unsigned address;
      int unsigned data;
      function new(string name = "bus_item"); super.new(name); endfunction
    endclass
    
    class base_object extends uvm_object;
      `uvm_object_utils(base_object)
      function new(string name = "base_object"); super.new(name); endfunction
    endclass
    
    class derived_object extends base_object;
      `uvm_object_utils(derived_object)
      function new(string name = "derived_object"); super.new(name); endfunction
    endclass
    
    class probe_callback extends uvm_callback;
      int calls;
      function new(string name = "probe_callback"); super.new(name); endfunction
      virtual function void observed(); calls++; endfunction
    endclass
    
    class bus_driver extends uvm_driver#(bus_item);
      `uvm_component_utils(bus_driver)
      `uvm_register_cb(bus_driver, probe_callback)
      int unsigned memory[int unsigned];
      int transfers;
      function new(string name, uvm_component parent); super.new(name, parent); endfunction
      task run_phase(uvm_phase phase);
        bus_item request;
        forever begin
          seq_item_port.get_next_item(request);
          if (request.write) memory[request.address] = request.data;
          else request.data = memory.exists(request.address) ? memory[request.address] : 0;
          transfers++;
          `uvm_do_callbacks(bus_driver, probe_callback, observed())
          $display("REVIEW_BUS|%0d|%0h|%08h", request.write, request.address, request.data);
          seq_item_port.item_done();
        end
      endtask
    endclass
    
    class register_adapter extends uvm_reg_adapter;
      `uvm_object_utils(register_adapter)
      function new(string name = "register_adapter"); super.new(name); endfunction
      function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw);
        bus_item item = bus_item::type_id::create("item");
        item.write = rw.kind == UVM_WRITE;
        item.address = rw.addr;
        item.data = rw.data;
        return item;
      endfunction
      function void bus2reg(uvm_sequence_item bus, ref uvm_reg_bus_op rw);
        bus_item item;
        if (!$cast(item, bus)) `uvm_fatal("ADAPTER", "Wrong bus item")
        rw.kind = item.write ? UVM_WRITE : UVM_READ;
        rw.addr = item.address;
        rw.data = item.data;
        rw.status = UVM_IS_OK;
      endfunction
    endclass
    
    class wide_register extends uvm_reg;
      `uvm_object_utils(wide_register)
      uvm_reg_field field;
      function new(string name = "wide_register"); super.new(name, 64, UVM_NO_COVERAGE); endfunction
      function void build();
        field = uvm_reg_field::type_id::create("field");
        field.configure(this, 64, 0, "RW", 0, 0, 1, 1, 0);
      endfunction
    endclass
    
    class register_block extends uvm_reg_block;
      `uvm_object_utils(register_block)
      wide_register value;
      function new(string name = "register_block"); super.new(name, UVM_NO_COVERAGE); endfunction
      function void build();
        value = wide_register::type_id::create("value");
        value.configure(this);
        value.build();
        default_map = create_map("map", 'h100, 4, UVM_LITTLE_ENDIAN, 1);
        default_map.add_reg(value, 'h20, "RW");
        lock_model();
      endfunction
    endclass
    
    class child_sequence extends uvm_sequence#(bus_item);
      `uvm_object_utils(child_sequence)
      static int parent_ok;
      function new(string name = "child_sequence"); super.new(name); endfunction
      task body();
        bus_item item = bus_item::type_id::create("item");
        parent_ok = get_parent_sequence() != null;
        start_item(item);
        item.write = 1; item.address = 'h40; item.data = 'hcafe;
        finish_item(item);
      endtask
    endclass
    
    class parent_sequence extends uvm_sequence#(bus_item);
      `uvm_object_utils(parent_sequence)
      function new(string name = "parent_sequence"); super.new(name); endfunction
      task body();
        child_sequence child = child_sequence::type_id::create("child");
        child.start(m_sequencer, this);
      endtask
    endclass
    
    class automatic_sequence extends uvm_sequence#(bus_item);
      `uvm_object_utils(automatic_sequence)
      static int runs;
      function new(string name = "automatic_sequence"); super.new(name); endfunction
      task body(); runs++; endtask
    endclass
    
    class legacy_sequence extends uvm_sequence#(bus_item);
      `uvm_object_utils(legacy_sequence)
      static int runs;
      function new(string name = "legacy_sequence"); super.new(name); endfunction
      task body(); runs++; endtask
    endclass
    
    class matrix_test extends uvm_test;
      `uvm_component_utils(matrix_test)
      uvm_sequencer#(bus_item) sequencer, wrapper_sequencer, instance_sequencer, legacy_sequencer;
      bus_driver driver;
      probe_callback callback;
      register_block model;
      register_adapter adapter;
      string phases;
      int config_value;
      bit factory_ok;
      function new(string name, uvm_component parent); super.new(name, parent); endfunction
      function void build_phase(uvm_phase phase);
        base_object created;
        derived_object derived;
        automatic_sequence instance_sequence;
        super.build_phase(phase);
        phases = "build";
        uvm_config_db#(int)::set(this, "", "value", 42);
        if (!uvm_config_db#(int)::get(this, "", "value", config_value))
          `uvm_fatal("CONFIG", "Missing config")
        base_object::type_id::set_type_override(derived_object::get_type());
        created = base_object::type_id::create("created");
        factory_ok = $cast(derived, created);
        sequencer = new("sequencer", this);
        wrapper_sequencer = new("wrapper_sequencer", this);
        instance_sequencer = new("instance_sequencer", this);
        legacy_sequencer = new("legacy_sequencer", this);
        driver = bus_driver::type_id::create("driver", this);
        callback = new();
        uvm_callbacks#(bus_driver, probe_callback)::add(driver, callback);
        model = register_block::type_id::create("model");
        model.build();
        adapter = register_adapter::type_id::create("adapter");
        uvm_config_db#(uvm_object_wrapper)::set(this, "wrapper_sequencer.main_phase", "default_sequence", automatic_sequence::get_type());
        instance_sequence = automatic_sequence::type_id::create("instance_sequence");
        uvm_config_db#(uvm_sequence_base)::set(this, "instance_sequencer.main_phase", "default_sequence", instance_sequence);
        uvm_config_db#(string)::set(this, "legacy_sequencer", "default_sequence", "legacy_sequence");
      endfunction
      function void connect_phase(uvm_phase phase);
        phases = {phases, ">connect"};
        driver.seq_item_port.connect(sequencer.seq_item_export);
        model.default_map.set_sequencer(sequencer, adapter);
        model.default_map.set_auto_predict(1);
      endfunction
      task run_phase(uvm_phase phase);
        parent_sequence sequence_value;
        uvm_status_e status;
        uvm_reg_data_t data;
        phase.raise_objection(this);
        phases = {phases, ">run"};
        sequence_value = parent_sequence::type_id::create("sequence_value");
        sequence_value.start(sequencer);
        model.value.write(status, 64'h01234567_89abcdef, UVM_FRONTDOOR, model.default_map);
        $display("REVIEW|reg_write_status|%0d", status);
        model.value.read(status, data, UVM_FRONTDOOR, model.default_map);
        $display("REVIEW|reg_read_status|%0d", status);
        $display("REVIEW|reg_read_data|%016h", data);
        $display("REVIEW|reg_mirror_data|%016h", model.value.get_mirrored_value());
        #10;
        $display("REVIEW|objection_total|%0d", phase.get_objection().get_objection_total());
        phase.drop_objection(this);
      endtask
      function void extract_phase(uvm_phase phase);
        phases = {phases, ">extract"};
      endfunction
      function void report_phase(uvm_phase phase);
        phases = {phases, ">report"};
        $display("REVIEW|phase_order|%s", phases);
        $display("REVIEW|config_value|%0d", config_value);
        $display("REVIEW|factory_override|%0d", factory_ok);
        $display("REVIEW|sequence_parent|%0d", child_sequence::parent_ok);
        $display("REVIEW|phase_default_sequences|%0d", automatic_sequence::runs);
        $display("REVIEW|legacy_default_sequence|%0d", legacy_sequence::runs);
        $display("REVIEW|callback_calls|%0d", callback.calls);
        $display("REVIEW|bus_transfers|%0d", driver.transfers);
        $display("REVIEW|done|1");
      endfunction
    endclass
    
    module feature_matrix;
      initial run_test("matrix_test");
      initial begin #10000; $fatal(1, "Review timeout"); end
    endmodule
    

    全部用例 · 证据摘要

    版本适用范围