日常记录(52)workshop整理

top的program中与case的class中。

1 导入UVM的方法

在top的program内部,import uvm_pkg::*,在Makefile的vcs中,添加-ntb_opts uvm-1.1选项

 

2 top的timeformat

系统函数,参数为:时间精度,时间小数,后缀,显示位宽

 

3 top的vcs选项

控制使用哪一个case(top下的case)                   +UVM_TESTCASE=

控制uvm_info的显示等级                                       +UVM_VERBOSITY=

 

4 生成vpd波形文件

+vcs+vpdpluson的vcs选项,生成vpd文件。使用dve打开。

+UVM_TR_RECORD将transaction的信息存入vpd文件中。

+UVM_LOG_RECORD将uvm_info的信息存入vpd文件中,其中用req.sprint方式输出更直观。

 

5 uvm类树继承关系

日常记录(52)workshop整理

 

 

6 打印拓扑关系、注册在工厂的类,以及配置的重载信息

依次如下

uvm_top.print_topology()

factory.print()

uvm_top.print()

 

UVM内部部分

1 uvm_info展开

内部有几个函数,主要利用uvm_report_enabled、 uvm_report_info实现。

 

2 \$size的sv函数

$size(param1, param2)
param1是被测量的变量,param2是测量的变量维度。1为最外层维度。

 

3 is_active的类型

在uvm_agent中,其类型为uvm_active_passive_enum

 

4 scb中的类顺序比较函数

uvm_in_order_class_comparator的使用。

最终report的过程中,m_matches、m_mismatches分别输出匹配和不匹配的个数。

为了在16路的交换机上进行包的对比,对应的tr也需要进行按照顺序的方式对比。

如果只有一路,直接将定义的uvm_anapysis_export给到uvm_in_order_class_comparator的before_export和after_export上,这样就接收后,是直接传入比较类中,无需imp了。

用了imp以后,imp将da进行识别,传入不同的比较类。

`ifndef _SCOREBOARD_SV_
`define _SCOREBOARD_SV_

`uvm_analysis_imp_decl(_before)
`uvm_analysis_imp_decl(_after)

class scoreboard extends uvm_scoreboard;
    // data or class properties
    `uvm_component_utils(scoreboard)
    uvm_analysis_imp_before#(packet, scoreboard) export_before;
    uvm_analysis_imp_after#(packet, scoreboard) export_after;
    uvm_in_order_class_comparator#(packet) comparator[16];

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

    virtual function void build_phase(uvm_phase phase);
        export_before = new("export_before", this);
        export_after = new("export_after", this);
        for (int i = 0; i < 16; i++) begin
            comparator[i] = uvm_in_order_class_comparator#(packet)::type_id::create(
                $sformatf("comparator[%0d]", i), this);
        end
    endfunction: build_phase

    virtual function void write_before(packet tr);
        `uvm_info($sformatf("SB_INPUT_GET%0d", tr.da), "scoreboard get a packet", UVM_LOW)
        comparator[tr.da].before_export.write(tr);
    endfunction: write_before

    virtual function void write_after(packet tr);
        `uvm_info($sformatf("SB_OUTPUT_GET%0d", tr.da), "scoreboard get a packet", UVM_LOW)
        comparator[tr.da].after_export.write(tr);
    endfunction: write_after

    virtual function void report_phase(uvm_phase phase);
        for (int i = 0; i < 16; i++) begin
            `uvm_info($sformatf("SB_REPORT[%0d]",i), $sformatf("Match %0d, MisMatch %0d",
                comparator[i].m_matches, comparator[i].m_mismatches[i]), UVM_LOW)
        end
    endfunction: report_phase
endclass : scoreboard
`endif

 

5 phase的顺序

https://blog.csdn.net/qq_37884273/article/details/114239843

一般在report这个phase的顶层输出点信息。比如上面的scb。

日常记录(52)workshop整理

 

 

 

6 设置drain_time

https://github.com/baimengwei/5pS-5Yiw566A5Y6G5LiK55qE56ys5LiA5Liq/blob/main/packet_sequence.sv#L37-L41

在发送端,给seq的body上的starting_phase设置。

1 获取objection:starting_phase.get_objection();

2 设置drain_time:objection.set_drain_time(this, 1us);

 

7 uvm_sequence_library说明

在上一段的第5个,说明了它是继承了seq的,因此设置它到seqr的default_sequence上,类型还是uvm_object_wrapper(uvm_config_db函数用到)。

1. 注册:

使用uvm_object_utils和`uvm_sequence_library_utils,还需要init_sequence_library;在new函数中。

https://github.com/baimengwei/5pS-5Yiw566A5Y6G5LiK55qE56ys5LiA5Liq/blob/main/packet_seq_lib_pkg.sv

2. 配置:

在case中配置时,先定义和实例化uvm_sequence_library_cfg,然后传给seq_lib的config中

        seq_cfg = new("seq_cfg", UVM_SEQ_LIB_RAND, 2, 2);
        uvm_config_db#(uvm_sequence_library_cfg)::set(
            this, "env.i_agt[*].seqr.main_phase", "default_sequence.config", seq_cfg);

https://github.com/baimengwei/5pS-5Yiw566A5Y6G5LiK55qE56ys5LiA5Liq/blob/main/test_collection.sv#L76-L78

3. 添加:

使用静态方法添加:packet_seq_lib是一个class,使用add_typewide_sequence添加seq到seq_lib中。

packet_seq_lib::add_typewide_sequence(packet_sequence::get_type());

https://github.com/baimengwei/5pS-5Yiw566A5Y6G5LiK55qE56ys5LiA5Liq/blob/main/test_collection.sv#L80

4. 修改:

seq_lib下的seq需要说明它的starting_phase不是seqr的,因此为null,它的starting_phase是seq_lib的,因此需要以下的get_parent_sequence。

同样参考继承关系,seq_lib和seq都是seq_base的,定义出的parent就是一个基类。

        uvm_sequence_base parent = get_parent_sequence();
        if (parent != null) begin
            starting_phase = parent.starting_phase;
        end

https://github.com/baimengwei/5pS-5Yiw566A5Y6G5LiK55qE56ys5LiA5Liq/blob/main/packet_sequence.sv#L32-L35

 

RAL设定

主工程代码:https://github.com/baimengwei/5pS-5Yiw566A5Y6G5LiK55qE56ys5LiA5Liq/

0:不使用ral方式,

和传统一样

定义agent、seqr、seq、drv,然后seq初始化,通过seqr发给drv,drv驱动获取数据(drv打印出来返回结果就行了)。

交互主要seq和drv。

 

1 ralf文件定义和生成:

https://github.com/baimengwei/5pS-5Yiw566A5Y6G5LiK55qE56ys5LiA5Liq/blob/main/host.ralf

其中的空格不可省去。the blank between id and bracket can't be ignored.

register HOST_ID {
  field REV_ID {
    bits 8;
    access ro;
    reset 'h03;
  }
  field CHIP_ID {
    bits 8;
    access ro;
    reset 'h5A;
  }
}

register PORT_LOCK {
  field LOCK {
    bits 16;
    access w1c;
    reset 'hffff;
  }
}

register REG_ARRAY {
  field USER_REG {
    bits 16;
    access rw;
    reset 'h0;
  }
}

memory RAM {
  size 4k;
  bits 16;
  access rw;
}

block host_regmodel {
  bytes 2;
  register HOST_ID        (host_id)       @'h0000;
  register PORT_LOCK      (lock)          @'h0100;
  register REG_ARRAY[256] (host_reg[%d])  @'h1000; # array must specify HDL index
  memory   RAM            (ram)           @'h4000;
}

 

2. 通过该ralf文件生成regmodel

https://github.com/baimengwei/5pS-5Yiw566A5Y6G5LiK55qE56ys5LiA5Liq/blob/main/Makefile#L31-L32

最终通过RALFILE文件生成的regmodel文件为:ral_RALPOSTFIX.sv。其中会有ral_block_RALPOSTFIX类。是uvm_reg_block的regmodel。

ralgen -uvm -t $(RALPOSTFIX) $(RALFILE)

 

3. 有了regmodel后,设置组件连接

定义好agent中指定的seqr、adapter、seq。

说明:

1.组件连接关系和数据流

其中的seqr就是普通的seqr,但是不再通过default_sequence带入seq,发送给drv。

seqr、drv、adapter、seq。

由上层的agent(case)的task_phase中创建seq,并赋予seq的regmodel值,然后发送(通过start)。

    virtual task configure_phase(uvm_phase phase);
        super.configure_phase(phase);
        `uvm_info("RAL_HOST_AGENT", $sformatf("%m"), UVM_MEDIUM)

        seq = ral_host_sequence::type_id::create("host_seq", this);
        seq.regmodel = this.regmodel;
        phase.raise_objection(this);
        seq.start(null);
        phase.drop_objection(this);

https://github.com/baimengwei/5pS-5Yiw566A5Y6G5LiK55qE56ys5LiA5Liq/blob/main/ral_host_agent.sv#L43-L52

其中的regmodel需要实例化和配置(注意seqr的设置):

regmodel中需要接入seqr和adapter,因此这里同时实例了seqr、adapter。

https://github.com/baimengwei/5pS-5Yiw566A5Y6G5LiK55qE56ys5LiA5Liq/blob/main/ral_host_agent.sv#L28-L35

    virtual function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        // switch to ral model 
        uvm_config_db#(uvm_object_wrapper)::set(this, "seqr.configure_phase", "default_sequence", null);
        // start.
        regmodel = ral_block_host_regmodel::type_id::create("ral_block_host_regmodel", this);
        adapter = reg_adapter::type_id::create("reg_adapter", this);

        uvm_config_db#(string)::get(this, "", "hdl_path", hdl_path);
        regmodel.build();
        regmodel.lock_model();
        regmodel.set_hdl_path_root(hdl_path); 
    endfunction: build_phase

在connect_phase接入:

https://github.com/baimengwei/5pS-5Yiw566A5Y6G5LiK55qE56ys5LiA5Liq/blob/main/ral_host_agent.sv#L38-L41

    virtual function void connect_phase(uvm_phase phase);
        super.connect_phase(phase);
        regmodel.default_map.set_sequencer(seqr, adapter);
    endfunction: connect_phase

 

2. adapter的新增的

继承uvm_reg_adapter,不是component。其中的reg2bus和bus2reg实现好。

日常记录(52)workshop整理

https://github.com/baimengwei/5pS-5Yiw566A5Y6G5LiK55qE56ys5LiA5Liq/blob/main/reg_adapter.sv

 

3. seq是特定的,也算新增了

继承uvm_reg_sequence,后者的继承关系需要自己定,默认继承于sequence即可。

日常记录(52)workshop整理

 

seq的内部body中,需要由外层传入的regmodel,实现regmodel的读写功能。此外需要数据、状态,用于控制。

 https://github.com/baimengwei/5pS-5Yiw566A5Y6G5LiK55qE56ys5LiA5Liq/blob/main/ral_host_sequence.sv

    virtual task body();
        uvm_status_e status;
        uvm_reg_data_t data;
        if (starting_phase!=null) begin
            starting_phase.raise_objection(this);
        end
        regmodel.PORT_LOCK.read(.status(status), .value(data), .path(UVM_FRONTDOOR), .parent(this));
        `uvm_info("RAL_READ", $sformatf("read_port_lock %0h", data), UVM_MEDIUM)
        regmodel.PORT_LOCK.write(.status(status), .value('1), .path(UVM_FRONTDOOR), .parent(this));
        `uvm_info("RAL_WRITE", $sformatf("read_port_lock %0h", data), UVM_MEDIUM)
        regmodel.PORT_LOCK.read(.status(status), .value(data), .path(UVM_FRONTDOOR), .parent(this));
        `uvm_info("RAL_READ", $sformatf("read_port_lock %0h", data), UVM_MEDIUM)
        if (starting_phase!=null) begin
            starting_phase.drop_objection(this);
        end
    endtask: body

 

上一篇:qfile读取txt文件


下一篇:LeetCode135-Candy