sequencer/sequence实验

本实验的目的是将generator重构成sequencer和sequence,其中,sequence是用来生成相应的sequence_item,sequencer用于发送sequence_item。
首先修改的是driver和generator之间的通信mailbox,我们不再使用mailbox进行transaction的传输。采用tlm端口进行,即在agent的connect_phase()方法中将agent的seq_item_port与sequencer的seq_item_export进行连接(由于chnl_package,reg_package以及fmt_package中generator是一致的,所以采用reg_package举例)。

driver.seq_item_port.connect(sequencer.seq_item_export);

这里之前报错,后来发现是因为参数化的类这个问题,我给driver声明的时候添加了#(reg_trans),但是sequener并没有添加#(reg_trans),这导致接口的类型不同,因此报错。
driver在run_phase()阶段调用get_next_item()方法获取sequencer上挂载的sequence产生的sequence_item。

seq_item_port.get_next_item(req);

driver在接收到sequence_item之后,对其进行克隆,调用核心基类的核心方法,产生的对象类型是uvm_object,需要通过cast将其转化为reg_trans这种sequence_item类型。之后通过调用item_done返回,在此之前,我们需要获得该Item所述的sequence的id,保证传输给相应的sequence。

rsp.set_sequence_id(req.get_sequence_id());
seq_item_port.item_done(rsp);

之后是对generator实现到sequence/sequencer的转化。首先是sequencer的声明,比较简单,就是利用`uvm_component_utils()完成sequencer的注册,并且声明new()函数。

class reg_sequencer extends uvm_sequencer #(reg_trans);
    `uvm_component_utils(reg_sequencer)
    function new(string name ="reg_sequencer",uvm_component parent);
       super.new(name,parent);
    endfunction
  endclass:reg_sequencer

之后是sequence产生test中相应的sequence_item,首先声明了相应的成员变量,并加以约束,约束采用soft软约束,以便virtual_sequence对其进行随机化。

    rand bit[7:0] addr = -1;
    rand bit[1:0] cmd = -1;
    rand bit[31:0] data = -1;
    constraint cstr{
      soft addr == -1;
      soft cmd == -1;
      soft data == -1;
    }

sequence挂载在sequencer之后,会执行task body()方法。在task_body()阶段,产生相应的sequence_item,并利用sequence中的成员变量对sequence_item进行约束,采用uvm_do_with()方法

`uvm_do_with(req,{local::addr >= 0 -> addr == local::addr;
                                 local::cmd >= 0 -> cmd == local::cmd;
                                 local::data >= 0 -> data == local::data;})

并利用get_response()获得driver的rsp,这里也发生了报错,也是因为sequence没有添加参数化类#(reg_trans)

get_response(rsp);

基于reg_base_sequence,我们可以产生很多继承于其的子类,用于寄存器的读/写/无操作。对于读这一sequence,只需要将cmd修改成读,写也类似。对于无操作,需要将cmd改成`idle,data和addr改成0。

接下来是对mcdf_package中的env以及test的重构。
首先在env中,需要添加virtual_sequencer这一组件,并将其中包含的sequencer句柄与之前底层的sequencer组件进行连接。
我们首先声明virtual_sequencer,这是一个组件,其中的成员变量是各个sequencer句柄,包含1个reg_sequencer的句柄,1个fmt_sequencer的句柄和3个chnl_sequencer的句柄。之后是对virtual_sequencer的注册。

 class mcdf_virtual_sequencer extends uvm_sequencer;
     reg_sequencer reg_sqr;
     fmt_sequencer fmt_sqr;
     chnl_data_sequencer chnl_sqrs[3];
     `uvm_component_utils(mcdf_virtual_sequencer)
     function new(string name = "mcdf_virtual_sequencer", uvm_component parent);
        super.new(name,parent);
     endfunction
  endclass: mcdf_virtual_sequencer

之后将virtual_sequencer句柄包含在env环境中,并在build_phase阶段创建virtual_sequencer组件,在connect_phase阶段将virtual_sequencer中包含的sequencer句柄,与底层的sequencer进行连接。

virt_sqr.reg_sqr = reg_agt.sequencer;
virt_sqr.fmt_sqr = fmt_agt.sequencer;
foreach(chnl_agts[i]) virt_sqr.chnl_sqrs[i] = chnl_agts[i].sequencer;

完成之后,我们需要将base_test拆分为base_sequence和base_test,这里,sequence用于产生相应需要的item,test作为一个空壳,在run_phase阶段实现virtual_sequence挂载在virtual_sequencer上。
对于virtual_sequence,包含的register的读/写/idle指令的sequence,以及fmt中对于fifo大小以及fifo带宽的sequence,以及产生三个channel数据的sequence句柄。

  idle_reg_sequence idle_reg_seq;
  write_reg_sequence write_reg_seq;
  read_reg_sequence read_reg_seq;
  fmt_sequence fmt_seq;
  chnl_data_sequence chnl_data_seq[3];

同样,virtual_sequence挂载于virtual_sequencer上,会执行其body()方法,在body()方法中执行do_reg(),do_formatter(),do_data()三个方法,这三个方法由于在不同的test中执行不同,我们在base_sequence中采用虚方法,以方便子类继承。
不可忽略的是,由于virtual_sequence中的sequence需要挂载在virtual_sequencer上,所以采用宏声明,将m_sequencer转化为p_sequencer。

`uvm_declare_p_sequencer(mcdf_virtual_sequencer)

之后在base_test中,在build_phase阶段利用uvm_config_db#(T)::get(this," ",“interface”,interface)来获取config_db数据库中的接口。在run_phase执行run_virtual_sequence()方法,该方法用于将virtual_sequence进行创建,并将其挂载在virtual_sequencer上。在后续可见。
例如,我们在consistence_test中将其拆分为consistence_sequence和consistence_test,对于cosnistence_sequence中do_reg()等方法进行重写,根据要求产生相应的sequence,并挂载在virtual_sequencer中的句柄上。

`uvm_do_on_with(write_reg_seq,p_sequencer.reg_sqr,{addr ==`SLV0_RW_ADDR;data == wr_val;})
`uvm_do_on_with(read_reg_seq,p_sequencer.reg_sqr,{addr == `SLV0_RW_ADDR;})

这是写/读的sequence的产生与挂载,其余均采用`uvm_do_on_with()方法。
对于test,只需要注册和重写run_virtual_sequence()这一虚方法。
即创建相应的virtual_sequence,并挂载在virtual_sequencer上。

top_seq = mcdf_data_consistence_basic_virtual_sequence::type_id::create("top_seq");
top_seq.start(env.virt_sqr);

以上就完成了generator向sequence/sequencer的转变。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一般来说,m_sequencer不会同时作为sequencesequence item的成员变量,因为它们是不同的类别。一般情况下,sequencesequence item是在SystemVerilog Testbench使用的,用于驱动和监测DUT。下面是一个示例代码,其包含sequencesequence item,并且它们都有自己的成员变量: ``` class my_sequence extends uvm_sequence #(my_sequence_item); rand int data; my_sequence_item seq_item; function new(string name = "my_sequence"); super.new(name); endfunction virtual task body(); // Generate sequence items repeat(10) begin seq_item = my_sequence_item::type_id::create("seq_item"); seq_item.data = $urandom_range(0, 10); seq_item.addr = $urandom_range(0, 1024); seq_item.size = 4; `uvm_info("my_sequence", $sformatf("Sequence item generated: addr=%0d, data=%0d", seq_item.addr, seq_item.data), UVM_MEDIUM) // Send sequence item to driver seq_item.randomize(); seq_item.set_starting_phase(get_starting_phase()); seq_item.set_parent_sequence(this); if(!seq_item.randomize()) `uvm_error("my_sequence", "Failed to randomize sequence item") if(!seq_item.send_request()) `uvm_error("my_sequence", "Failed to send sequence item") // Wait for response from DUT if(!seq_item.grab_response()) `uvm_error("my_sequence", "Failed to grab response for sequence item") end endtask endclass class my_sequence_item extends uvm_sequence_item; rand int data; int addr; int size; `uvm_object_utils(my_sequence_item) function new(string name = "my_sequence_item"); super.new(name); endfunction function void do_print (uvm_printer printer); super.do_print(printer); printer.print_field("data", data, $bits(data), UVM_HEX); printer.print_field("addr", addr, $bits(addr), UVM_HEX); printer.print_field("size", size, $bits(size), UVM_DEC); endfunction endclass ``` 在这个示例代码,my_sequence类表示一个sequence,my_sequence_item类表示一个sequence item。它们都有自己的成员变量,例如my_sequence的data和seq_item,以及my_sequence_item类的data、addr和size。没有一个名为m_sequencer的成员变量,因为它们都是在uvm_sequence和uvm_sequence_item的基础上定义的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值