目录
uvm_reg_adapter和uvm_reg_block的关系?
adapter,block,predictor三者的关系是什么?
1.2 在mcdf_env中声明并例化block、adapter、predictor,最后connect起来
2.2 mcdf_data_consistence_basic_virtual_sequence中原来是由总线seq实现的reg读写,现在改为由rgm操作的reg读写方式
2.3 mcdf_full_random_virtual_sequence做相同的操作,改为由rgm预先设置寄存器值,再统一做总线寄存器更新的方式,稍后由后门读取的方式取得寄存器值加以比较。

- uvm_reg_field reserved;
- rand uvm_reg_field pkt_len;//声明域,且可以随机化
- rand uvm_reg_field prio_level;
- rand uvm_reg_field chnl_en;
-
- reserved = uvm_reg_field::type_id::create("");
- pkt_len = uvm_reg_field::type_id::create("");
- prio_level = uvm_reg_field::type_id::create("");
- chnl_en = uvm_reg_field::type_id::create("");//例化
-
- reserved.configure(this, 26, 6, "RO", 0, 26'h0, 1, 0 , 0);//配置
- pkt_len.configure(this,3,3,"RW",0,3'h0,1,1,0);//前两个表示位,后面的具体数表示默认值
- prio_level.configure(this,2,1,"RW",0,2'h3,1,1,0);
- chnl_en.configure(this,1,0,"RW",0,1'h0,1,1,0);
- class reg2mcdf_adapter extends uvm_reg_adapter;
- `uvm_object_utils()
- function new(string name ="");
- super.new(name);
- provides_responses=1;//enable了provides_responses,总线可以返回rsp的数据
- endfunction
-
- //预定义的,也是必须实现的,名字一个字都不能差
- function uvm_sequence_item reg2bus (const ref uvm_reg_bus_op rw);
- mcdf_bus_trans t=mcdf_bus_trnas::type_id::create("t");//创建子类对象
- t.cmd=(rw.kind == UVM_WRITE)? `WRITE : `READ;
- t.addr=rw.addr;
- t.wdata=rw.data;
- return t;//做了隐式转换
- endfunction//完成了寄存器级别操作rw到bus上的桥接,下面的func反之
-
- function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw);
- //从driver将数据写会sequencer,adapter从sqr拿到rsp(t)后自动调用
- mcdf_bus_trans t;
- if(!$cast(t, bus_item)) begin//父类句柄,转换成子类mcdf_bus_trans句柄
- `uvm_fatal("", "")
- return; end
- rw.kind=(t.cmd==`WRITE)? UVM_WRITE : UVM_READ;//转换后才可以访问子类对象
- rw.addr=t.addr;
- rw.data=(t.cmd==`WRITE)? t.wdata : t.rdata;
- rw.status=UVM_IS_OK;
- endfunction
- endclass
- class mcdf_bus_env extends uvm_env;
- mcdf_bus_agent agent;
- mcdf_rgm rgm;
- reg2mcdf_adapter reg2mcdf;//先声明
- ...//注册+例化
- function void build_phase(u p);
- agent=mcdf_bus_agent::type_id::create("", this);
- if(!uvm_config_db#(mcdf_rgm)::get(this, "", "rgm", rgm)) begin
- `uvm_info()
- rgm=mcdf_rgm::type_id::create("", this);
- end
- rgm.build();//创建,配置reg,调用各个reg的build,以及它们的field
- rgm.map.set_auto_predict();//还没集成predictor,所以调用set_auto_predict(),采用auto prediction方式
- reg2mcdf=reg2mcdf_adapter::type_id::create("");//例化adapter
- endfunction
-
- function void connect_phase(u p);
- rgm.map.set_sequencer(agent.sequencer, reg2mcdf);//!连接:将adapter连接到sequencer上
- endfunction
- endclass
-
- class test1 extends uvm_test;
- mcdf_rgm rgm;
- mcdf_bus_env env;
- ...//注册+例化
- function void build_phase(u p);
- rgm=mcdf_rgm::type_id::create("", this);
- uvm_config_db#(mcdf_rgm)::set(this, "env*", "rgm", rgm)
- env=mcdf_bus_env::type_id::create("", this);
- endfunction
- task run_phase(u p); ...
- endclass
- //和上一段代码的差别并不大,注释的部分就是新加的
- class mcdf_bus_env extends uvm_env;
- mcdf_bus_agent agent;
- mcdf_rgm rgm;
- reg2mcdf_adapter reg2mcdf;
- uvm_reg_predictor mcdf2reg_predictor;//先声明
- ...
- function void build_phase(u p);
- agent=mcdf_bus_agent::type_id::create("", this);
- if(!uvm_config_db#(mcdf_rgm)::get(this, "", "rgm", rgm)) begin
- `uvm_info()
- rgm=mcdf_rgm::type_id::create("", this);
- end
- rgm.build();
- mcdf2reg_predictor=uvm_reg_predictor::type_id::create("",this);//例化
- reg2mcdf=reg2mcdf_adapter::type_id::create("");
- mcdf2reg_predictor.map=rgm.map;//把rgm的map给到predictor的map
- mcdf2reg_predictor.adapter=reg2mcdf;//把rgm的adapter给到predictor的map
- endfunction
-
- function void connect_phase(u p);
- rgm.map.set_sequencer(agent.sequencer, reg2mcdf);
- agent.monitor.ap.connect(mcdf2reg_predictor.bus_in);//!连接:将adapter连接到sequencer上
- endfunction
- endclass


- class mcdf_example_seq extends uvm_reg_sequence;
- mcdf_rgm rgm;
- `uvm_object_utils()
- `uvm_declare_p_sequencer()
- ...
- task body();
- uvm_status_e status;
- uvm_reg_data_t data;
- uvm_reg_hw_reset_seq reg_rst_seq=new();//先例化
- uvm_reg_bit_bash_seq reg_bit_bas_seq=new();
- uvm_reg_access_seq reg_acc_seq=new();
- if(!uvm_config_db#(mcdf_rgm)::get(null, get_full_name(), "rgm", rgm)) begin
- `uvm_error() end
- @(negedge p_sequencer.vif.rstn);
- @(posedge p_sequencer.vif.rstn);
- `uvm_info()
- reg_rst_seq.model=rgm;//给模型
- reg_rst_seq.start(m_sequencer);//start即可
- `uvm_info()
- `uvm_info()
- reg_bit_bash_seq.model=rgm;
- reg_bit_bash_seq.start(m_sequencer);
- `uvm_info()
- `uvm_info()
- reg_acc_seq.model=rgm;
- reg_acc_seq.start(m_sequencer);
- `uvm_info()
- endtask
- endclass
- //缺点:默认采样所有field,不够灵活不够智能
- class ctrl_reg extends uvm_reg;
- `uvm_object_utils(ctrl_reg)
- uvm_reg_field reserved;
- rand uvm_reg_field pkt_len;
- rand uvm_reg_field prio_level;
- rand uvm_reg_field chnl_en;
-
- covergroup value_cg;//定义一个覆盖组
- option.per_instance=1;
- reserved: coverpoint reserved.value[25:0];
- pkt_len: coverpoint pkt_len.value[2:0];
- prio_level: coverpoint prio_level.value[1:0];
- chnl_en: coverpoint chnl_en.value[0:0];
- endgroup
-
- function new(string name ="ctrl_reg");
- super.new(name, 32, UVM_CVR_ALL);//UVM_NO_COVERAGE改为UVM_CVR_ALL
- set_coverage(has_coverage(UVM_CVR_FIELD_VALS)); begin
- //has_coverage()查询ctrl_reg::m_has_cover是否具备特定的覆盖率类型,判断是否需要例化
- //是否具备对应的covergroup?->是否例化?
- //由于上面new已经是UVM_CVR_ALL,所以可以例化
- value_cg=new(); end//covergroup例化
- endfunction
-
- virtual function build();//这个没有变化
- reserved = uvm_reg_field::type_id::create("");
- pkt_len = uvm_reg_field::type_id::create("");
- prio_level = uvm_reg_field::type_id::create("");
- chnl_en = uvm_reg_field::type_id::create("");
- reserved.configure(this, 26, 6, "RO", 0, 26'h0, 1, 0 , 0);
- pkt_len.configure(this,3,3,"RW",0,3'h0,1,1,0);
- prio_level.configure(this,2,1,"RW",0,2'h3,1,1,0);
- chnl_en.configure(this,1,0,"RW",0,1'h0,1,1,0);
- endfunction
-
- function void sample(uvm_reg_data_t data,//理解为读写方法的回调函数
- uvm_reg_data_t byte_en,
- bit is_read,
- uvm_reg_map ,ap);
- super.sample(data, byte_en, is_read, map);
- sample_values();
- endfunction
-
- function void sample_values();//外部调用时ctrl_reg::sample_values()
- super.sample_values();
- if(get_coverage(UVM_CVR_FIELD_VALS)) begin
- //是否允许使用对应的covergroup进行采样,->是否采样?
- value_cg.sample(); end
- endfunction
- endclass
- //定义一个覆盖率class
- class mcdf_coverage extends uvm_subscriber #(mcdf_bus_trans);
- //信息来自于mcdf_bus_monitor,通过其uvm_analysis_port发到
- //mcdf_coverage的uvm_analysis_export
- mcdf_rgm rgm;
- `uvm_component_utils(mcdf_coverage)
-
- covergroup reg_value_cg;
- option.per_instance=1;
- //指定了感兴趣的field和值范围
- CH0LEN: coverpoint rgm.chnl0_ctrl_reg.pkt_len.value[2:0] {bins len[]={0,1,2,3,[4:7]};}
- CH0PRI: coverpoint rgm.chnl0_ctrl_reg.prio_level.value[1:0];
- CH0CEN: coverpoint rgm.chnl0_ctrl_reg.chnl_en.value[0:0];
- CH1LEN: coverpoint rgm.chnl1_ctrl_reg.pkt_len.value[2:0] {bins len[]={0,1,2,3,[4:7]};}
- CH1PRI: coverpoint rgm.chnl1_ctrl_reg.prio_level.value[1:0];
- CH1CEN: coverpoint rgm.chnl1_ctrl_reg.chnl_en.value[0:0];
- CH2LEN: coverpoint rgm.chnl2_ctrl_reg.pkt_len.value[2:0] {bins len[]={0,1,2,3,[4:7]};}
- CH2PRI: coverpoint rgm.chnl2_ctrl_reg.prio_level.value[1:0];
- CH2CEN: coverpoint rgm.chnl2_ctrl_reg.chnl_en.value[0:0];
- CH0AVL: coverpoint rgm.chnl0_stat_reg.fifo_avail.value[7:0] {bins avail[]={0,1,[2:7],[8:55],[56:61], 62, 63};}
- CH1AVL: coverpoint rgm.chnl1_stat_reg.fifo_avail.value[7:0] {bins avail[]={0,1,[2:7],[8:55],[56:61], 62, 63};}
- CH2AVL: coverpoint rgm.chnl2_stat_reg.fifo_avail.value[7:0] {bins avail[]={0,1,[2:7],[8:55],[56:61], 62, 63};}
- LEN_COMB: cross CH0LEN, CH1LEN, CH2LEN;//cross是干嘛的?待查
- PRI_COMB: cross CH0PRI, CH1PRI, CH2PRI;
- CEN_COMB: cross CH0CEN, CH1CEN, CH2CEN;
- AVL_COMB: cross CH0AVL, CH1AVL, CH2AVL;
- endgroup
-
- function new(string name, uvm_component parent);//这个是component,要有parent
- if(!uvm_config_db #(mcdf_rgm)::get(this, "", "rgm", rgm)) begin
- `uvm_info() end
- reg_value_cg=new();
- endfunction
-
- function void write(T t);
- reg_value_cg.sample();
- endfunction
- endclass
声明所有的寄存器+map,class必有new函数。在build函数对所有reg进行例化、配置、build(),对map例化,加入寄存器到map
- class mcdf_rgm extends uvm_reg_block;
- `uvm_object_utils(mcdf_rgm)
- rand ctrl_reg chnl0_ctrl_reg;
- rand ctrl_reg chnl1_ctrl_reg;
- rand ctrl_reg chnl2_ctrl_reg;
- rand stat_reg chnl0_stat_reg;
- rand stat_reg chnl1_stat_reg;
- rand stat_reg chnl2_stat_reg;
- uvm_reg_map map;
- function new(string name ="")
- super.new(name, UVM_NO_COVERAGE);
- endfunction
-
- virtual function build();
- chnl0_ctrl_reg=ctrl_reg::type_id::create("");
- chnl0_ctrl_reg.configure(this);//创建,配置,
- chnl0_ctrl_reg.build();
- chnl1_ctrl_reg=ctrl_reg::type_id::create("");
- chnl1_ctrl_reg.configure(this);
- chnl1_ctrl_reg.build();
- chnl2_ctrl_reg=ctrl_reg::type_id::create("");
- chnl2_ctrl_reg.configure(this);
- chnl2_ctrl_reg.build();
- chnl0_stat_reg=stat_reg::type_id::create("");
- chnl0_stat_reg.configure(this);
- chnl0_stat_reg.build();
- chnl1_stat_reg=stat_reg::type_id::create("");
- chnl1_stat_reg.configure(this);
- chnl1_stat_reg.build();
- chnl2_stat_reg=stat_reg::type_id::create("");
- chnl2_stat_reg.configure(this);
- chnl2_stat_reg.build();
- map=create_map("map", 'h0, 4, UVM_LITTLE_ENDIAN);//map名字,基地址,位宽,endianess
- map.add_reg(chnl0_ctrl_reg, 32'h00000000, "RW");//偏移地址offset addr
- map.add_reg(chnl1_ctrl_reg, 32'h00000004, "RW");//完整reg地址addr=base addr+offset addr
- map.add_reg(chnl2_ctrl_reg, 32'h00000008, "RW");
- map.add_reg(chnl0_stat_reg, 32'h00000010, "RO");//添加每个reg的偏移地址和访问属性(模式)
- map.add_reg(chnl1_stat_reg, 32'h00000014, "RO");
- map.add_reg(chnl2_stat_reg, 32'h00000018, "RO");
- lock_model();//reg构建后锁住这个模型,不允许外部访问寄存器内部,只可以用预测组件来改变
- endfunction
- endclass
- class mcdf_bus_trans extends uvm_sequence_item;
- rand bit[1:0] cmd;
- rand bit[7:0] addr;
- rand bit[31:0] data;
- bit[31:0] rdata;//从总线读回来的,不可随机化
- `uvm_object_utils_begin()...//注册以及域的自动化
- ...endclass
-
- class mcdf_bus_sequencer extends uvm_sequencer;
- virtual mcdf_if vif;
- `uvm_component_utils()
- ...//注册,例化
- function void build_phase(u p);
- if(!uvm_config_db#(virtual mcdf_if)::get(this, "", "vif", vif))begin
- `uvm_error("", "") end
- endfunction
- endclass
-
- class mcdf_bus_monitor extends uvm_monitor;//等下连接到uvm_reg_predictor
- virtual mcdf_if vif;
- uvm_analysis_port #(mcdf_bus_trans) ap;//monitor要广播
- `uvm_component_utils()
- ...
- function void build_phase(u p);
- if(!uvm_config_db#(virtual mcdf_if)::get(this, "", "vif", vif))begin
- `uvm_error("", "") end
- ap =new("", this);//不能用create,因为port不是object
- endfunction
- task run_phase(u p);
- forever begin
- mon_trnas() end
- endtask
- task mon_trans();
- mcdf_bus_trans t;
- @(posedge vif.clk);
- if(vif.cmd==`WRITE) begin
- t=new();
- t.cmd=`WRITE;
- t.addr=vif.addr;
- t.wdata=vif.wdata;
- ap.write(t);
- end
- else if(vif.cmd==`READ) begin
- t=new();
- t.cmd=`READ;
- t.addr=vif.addr;
- fork begin//等下一个周期
- @(posedge vif.clk);
- #10ps;
- t.rdata=vif.rdata;
- ap.write(t); end
- join_none//的同时不错过下一拍
- end
- endtask
- endclass
-
- class mcdf_bus_driver extends uvm_driver;
- virtual mcdf_if vif;
- ...//注册+例化
- function void build_phase(u p);
- if(!uvm_config_db#(virtual mcdf_if)::get(this, "", "vif", vif))begin
- `uvm_error("", "") end
- endfunction
- task run_phase(u p);
- REQ tmp;
- mcdf_bus_trans req, rsp;
- reset_listener();
- forever begin
- seq_item_port.get_next_item(tmp);
- void'($cast(req,tmp));
- `uvm_info("got")
- void'($cast(rsp, req.clone()));
- rsp.set_sequence_id(req.get_sequence_id());
- rsp.set_transaction_id(req.get_transaction_id());
- driver_bus(rsp);
- set_item_port.item_done(rsp);
- `uvm_info("sent")
- end
- endtask
- task reset_listener();
- fork
- forever begin
- @(negdege vif.rstn) drive_idle();
- end
- join_none
- endtask
- task drive_bus(mcdf_bus_trans t);
- case (t.cmd)
- `WRITE:drive_write(t);
- `READ :drive_read(t);
- `IDLE :drive_idle();
- default: `uvm_error()
- endcase
- endtask
- task drive_write(mcdf_bus_trans t);
- @(posedge vif.clk);
- vif.cmd<=t.cmd;
- vif.addr<=t.addr;
- vif.data<=t.wdata;
- endtask
- task drive_read(mcdf_bus_trans t);
- @(posedge vif.clk);
- vif.cmd<=t.cmd;
- vif.addr<=t.addr;
- @(posedge vif.clk);
- #10ps;
- t.rdata=vif.rdata;
- endtask
- task drive_idle(bit is_sync=0);
- if(is_sync) @(posedge vif.clk);
- vif.cmd<='h0;
- vif.addr<='h0;
- vif.data<='h0;
- endtask
- endclass
- class mcdf_bus_agent extends uvm_agent;
- mcdf_bus_driver driver;
- mcdf_bus_sequencer sequencer;
- mcdf_bus_monitor monitor;
- ...
- function void build_phase(u p);
- driver =mcdf_bus_driver::type_id::create("", this);
- sequencer=mcdf_bus_sequencer::type_id::create("", this);
- monitor =mcdf_bus_monitor::type_id::create("", this);
- endfunction
- function void connect_phase(u p);
- driver.seq_item_port.connect(sequencer.seq_item_export);
- endfunction
- endclass
这里是对应adapter的定义,主要就是两个方法的书写,一个是reg2bus,另一个是bus2reg,在做reg和总线的转换之间。
先复习一下之前的例码
- function uvm_sequence_item reg2bus (const ref uvm_reg_bus_op rw);
- mcdf_bus_trans t=mcdf_bus_trnas::type_id::create("t");
- t.cmd=(rw.kind == UVM_WRITE)? `WRITE : `READ;
- t.addr=rw.addr;
- t.wdata=rw.data;
- return t;
- endfunction
-
- function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw);
- //从driver将数据写会sequencer,adapter从sqr拿到rsp(t)后自动调用
- mcdf_bus_trans t;
- if(!$cast(t, bus_item)) begin
- `uvm_fatal("", "")
- return; end
- rw.kind=(t.cmd==`WRITE)? UVM_WRITE : UVM_READ;
- rw.addr=t.addr;
- rw.data=(t.cmd==`WRITE)? t.wdata : t.rdata;
- rw.status=UVM_IS_OK;
- endfunction
实验5代码如下,rgm是单独的pkg文件
- class reg2mcdf_adapter extends uvm_reg_adapter;
- `uvm_object_utils(reg2mcdf_adapter)
- function new(string name = "reg2mcdf_adapter");
- super.new(name);
- provides_responses = 1;//一样需要置1
- endfunction
- function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw);
- reg_trans t = reg_trans::type_id::create("t");//例化寄存器事务的句柄
- t.cmd = (rw.kind == UVM_WRITE) ? `WRITE : `READ;
- t.addr = rw.addr;//完全相同,判断cmd后将信息给到对象上
- t.data = rw.data;
- return t;
- endfunction
- function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw);
- reg_trans t;//声明
- if (!$cast(t, bus_item)) begin//总线句柄转换成子类reg事务句柄
- `uvm_fatal("CASTFAIL","Provided bus_item is not of the correct type")
- return;
- end
- rw.kind = (t.cmd == `WRITE) ? UVM_WRITE : UVM_READ;//完全相同
- rw.addr = t.addr;
- rw.data = t.data;
- rw.status = UVM_IS_OK;
- endfunction
- endclass
也就是集成到env中,先声明,build_phase中创建对象并传递对应地图,最后connect_phase连接ap端口。
先复习下例码的继承adapter+predictor
- //和上一段代码的差别并不大,注释的部分就是新加的
- class mcdf_bus_env extends uvm_env;
- mcdf_bus_agent agent;
- mcdf_rgm rgm;
- reg2mcdf_adapter reg2mcdf;
- uvm_reg_predictor mcdf2reg_predictor;//先声明
- ...
- function void build_phase(u p);
- agent=mcdf_bus_agent::type_id::create("", this);
- if(!uvm_config_db#(mcdf_rgm)::get(this, "", "rgm", rgm)) begin
- `uvm_info()
- rgm=mcdf_rgm::type_id::create("", this);
- end
- rgm.build();
- mcdf2reg_predictor=uvm_reg_predictor::type_id::create("",this);//例化
- reg2mcdf=reg2mcdf_adapter::type_id::create("");
- mcdf2reg_predictor.map=rgm.map;//把rgm的map给到predictor的map
- mcdf2reg_predictor.adapter=reg2mcdf;//把rgm的adapter给到predictor的map
- endfunction
-
- function void connect_phase(u p);
- rgm.map.set_sequencer(agent.sequencer, reg2mcdf);
- agent.monitor.ap.connect(mcdf2reg_predictor.bus_in);//!连接:将adapter连接到sequencer上
- endfunction
- endclass
实验5代码如下:
- class mcdf_env extends uvm_env;
- chnl_agent chnl_agts[3];
- reg_agent reg_agt;
- fmt_agent fmt_agt;
- mcdf_checker chker;
- mcdf_coverage cvrg;
- mcdf_virtual_sequencer virt_sqr;
- mcdf_rgm rgm;//声明三者的句柄
- reg2mcdf_adapter adapter;
- uvm_reg_predictor #(reg_trans) predictor;
-
- `uvm_component_utils(mcdf_env)
-
- function new (string name = "mcdf_env", uvm_component parent);
- super.new(name, parent);
- endfunction
-
- function void build_phase(uvm_phase phase);
- super.build_phase(phase);
- this.chker = mcdf_checker::type_id::create("chker", this);
- foreach(chnl_agts[i]) begin
- this.chnl_agts[i] = chnl_agent::type_id::create($sformatf("chnl_agts[%0d]",i), this);
- end
- this.reg_agt = reg_agent::type_id::create("reg_agt", this);
- this.fmt_agt = fmt_agent::type_id::create("fmt_agt", this);
- this.cvrg = mcdf_coverage::type_id::create("cvrg", this);
- virt_sqr = mcdf_virtual_sequencer::type_id::create("virt_sqr", this);
- //进行例化,注意rgm还要手动调用build
- rgm = mcdf_rgm::type_id::create("rgm", this);
- rgm.build();
- adapter = reg2mcdf_adapter::type_id::create("adapter", this);
- predictor = uvm_reg_predictor#(reg_trans)::type_id::create("predictor", this);
- endfunction
-
- function void connect_phase(uvm_phase phase);
- super.connect_phase(phase);
- chnl_agts[0].monitor.mon_bp_port.connect(chker.chnl0_bp_imp);
- chnl_agts[1].monitor.mon_bp_port.connect(chker.chnl1_bp_imp);
- chnl_agts[2].monitor.mon_bp_port.connect(chker.chnl2_bp_imp);
- reg_agt.monitor.mon_bp_port.connect(chker.reg_bp_imp);
- fmt_agt.monitor.mon_bp_port.connect(chker.fmt_bp_imp);
- virt_sqr.reg_sqr = reg_agt.sequencer;
- virt_sqr.fmt_sqr = fmt_agt.sequencer;
- foreach(virt_sqr.chnl_sqrs[i]) virt_sqr.chnl_sqrs[i] = chnl_agts[i].sequencer;
- //进行连接
- rgm.map.set_sequencer(reg_agt.sequencer, adapter);
- //连接adapter到reg的agent中的sequencer。rgm的连接时调用map中的set_sequencer
- reg_agt.monitor.mon_ana_port.connect(predictor.bus_in);
- //monitor的ap连接到predictor的bus_in
- predictor.map = rgm.map;//rgm的map和adapter配置到predictor
- predictor.adapter = adapter;
-
- virt_sqr.rgm = rgm;
- endfunction
- endclass: mcdf_env
在上面例码中的connect_phase,将rgm对象给到vser中的rgm句柄
- //TODO-2.1 connect the virtual sequencer's rgm handle with rgm object
- virt_sqr.rgm = rgm;
在vser类mcdf_base_virtual_sequence的body()中,将p_sequencer的rgm赋给rgm句柄
- class mcdf_base_virtual_sequence extends uvm_sequence;
- idle_reg_sequence idle_reg_seq;
- write_reg_sequence write_reg_seq;
- read_reg_sequence read_reg_seq;
- chnl_data_sequence chnl_data_seq;
- fmt_config_sequence fmt_config_seq;
- mcdf_rgm rgm;
-
- `uvm_object_utils(mcdf_base_virtual_sequence)
- `uvm_declare_p_sequencer(mcdf_virtual_sequencer)
-
- function new (string name = "mcdf_base_virtual_sequence");
- super.new(name);
- endfunction
-
- virtual task body();
- `uvm_info(get_type_name(), "=====================STARTED=====================", UVM_LOW)
- //TODO-2.1 connect rgm handle
- rgm = p_sequencer.rgm;
-
- this.do_reg();
- this.do_formatter();
- this.do_data();
-
- `uvm_info(get_type_name(), "=====================FINISHED=====================", UVM_LOW)
- endtask
-
-
- virtual task do_reg();
- endtask
- virtual task do_formatter();
- endtask
- virtual task do_data();
- endtask
-
- virtual function bit diff_value(int val1, int val2, string id = "value_compare");
- if(val1 != val2) begin
- `uvm_error("[CMPERR]", $sformatf("ERROR! %s val1 %8x != val2 %8x", id, val1, val2))
- return 0;
- end
- else begin
- `uvm_info("[CMPSUC]", $sformatf("SUCCESS! %s val1 %8x == val2 %8x", id, val1, val2), UVM_LOW)
- return 1;
- end
- endfunction
- endclass
原来的 rd_val = read_reg_seq.data;和`uvm_do_on_with()被替换成rgm.对应rge.write/read
总线seq实现reg读写是利用了uvm提供的`uvm_do_on_with(),
- class mcdf_data_consistence_basic_virtual_sequence extends mcdf_base_virtual_sequence;
- `uvm_object_utils(mcdf_data_consistence_basic_virtual_sequence)
- function new (string name = "mcdf_data_consistence_basic_virtual_sequence");
- super.new(name);
- endfunction
- task do_reg();
- bit[31:0] wr_val, rd_val;
- uvm_status_e status;//这里多声明了status
- // slv0 with len=8, prio=0, en=1
- wr_val = (1<<3)+(0<<1)+1;
- //`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;})
- //将原来用do on with做的换成rgm的read和write
- rgm.chnl0_ctrl_reg.write(status, wr_val);
- rgm.chnl0_ctrl_reg.read(status, rd_val);
- //rd_val = read_reg_seq.data;
- void'(this.diff_value(wr_val, rd_val, "SLV0_WR_REG"));
- // slv1 with len=16, prio=1, en=1
- wr_val = (2<<3)+(1<<1)+1;
- //`uvm_do_on_with(write_reg_seq, p_sequencer.reg_sqr, {addr == `SLV1_RW_ADDR; data == wr_val;})
- //`uvm_do_on_with(read_reg_seq, p_sequencer.reg_sqr, {addr == `SLV1_RW_ADDR;})
- //rd_val = read_reg_seq.data;
- rgm.chnl1_ctrl_reg.write(status, wr_val);
- rgm.chnl1_ctrl_reg.read(status, rd_val);
- void'(this.diff_value(wr_val, rd_val, "SLV1_WR_REG"));
-
- // slv2 with len=32, prio=2, en=1
- wr_val = (3<<3)+(2<<1)+1;
- //`uvm_do_on_with(write_reg_seq, p_sequencer.reg_sqr, {addr == `SLV2_RW_ADDR; data == wr_val;})
- //`uvm_do_on_with(read_reg_seq, p_sequencer.reg_sqr, {addr == `SLV2_RW_ADDR;})
- //rd_val = read_reg_seq.data;
- rgm.chnl2_ctrl_reg.write(status, wr_val);
- rgm.chnl2_ctrl_reg.read(status, rd_val);
- void'(this.diff_value(wr_val, rd_val, "SLV2_WR_REG"));
- // send IDLE command
- `uvm_do_on(idle_reg_seq, p_sequencer.reg_sqr)
- endtask
- task do_formatter();
- `uvm_do_on_with(fmt_config_seq, p_sequencer.fmt_sqr, {fifo == LONG_FIFO; bandwidth == HIGH_WIDTH;})
- endtask
- task do_data();
- fork
- `uvm_do_on_with(chnl_data_seq, p_sequencer.chnl_sqrs[0], {ntrans==100; ch_id==0; data_nidles==0; pkt_nidles==1; data_size==8; })
- `uvm_do_on_with(chnl_data_seq, p_sequencer.chnl_sqrs[1], {ntrans==100; ch_id==1; data_nidles==1; pkt_nidles==4; data_size==16;})
- `uvm_do_on_with(chnl_data_seq, p_sequencer.chnl_sqrs[2], {ntrans==100; ch_id==2; data_nidles==2; pkt_nidles==8; data_size==32;})
- join
- #10us; // wait until all data haven been transfered through MCDF
- endtask
- endclass: mcdf_data_consistence_basic_virtual_sequence
//TODO-2.3 Follow the instructions below
// -reset the register block
// -set all value of WR registers via uvm_reg::set()
// -update them via uvm_reg_block::update()
// -compare the register value via uvm_reg::mirror() with backdoor access
- class mcdf_full_random_virtual_sequence extends mcdf_base_virtual_sequence;
- `uvm_object_utils(mcdf_base_virtual_sequence)
- function new (string name = "mcdf_base_virtual_sequence");
- super.new(name);
- endfunction
- //最顶格开始的为修改代码
- task do_reg();
- //bit[31:0] wr_val, rd_val;
- bit[31:0] ch0_wr_val;//换成三个,不需要rd_val
- bit[31:0] ch1_wr_val;
- bit[31:0] ch2_wr_val;
- uvm_status_e status;
- rgm.reset();//重启reg block
- // slv0 with len={4,8,16,32}, prio={[0:3]}, en={[0:1]}原来是要*3
- //wr_val = ($urandom_range(0,3)<<3)+($urandom_range(0,3)<<1)+$urandom_range(0,1);
- //`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;})
- //rd_val = read_reg_seq.data;
- //void'(this.diff_value(wr_val, rd_val, "SLV0_WR_REG"));
- ch0_wr_val = ($urandom_range(0,3)<<3)+($urandom_range(0,3)<<1)+$urandom_range(0,1);
- ch1_wr_val = ($urandom_range(0,3)<<3)+($urandom_range(0,3)<<1)+$urandom_range(0,1);
- ch2_wr_val = ($urandom_range(0,3)<<3)+($urandom_range(0,3)<<1)+$urandom_range(0,1);
- rgm.chnl0_ctrl_reg.set(ch0_wr_val);
- rgm.chnl1_ctrl_reg.set(ch1_wr_val);//通过uvm_reg::set()设置rgm中reg的wr_val
- rgm.chnl2_ctrl_reg.set(ch2_wr_val);
- rgm.update(status);//通过uvm_reg_block::update()刷新rgm数据
- #100ns;//等待dut中update完成
- rgm.chnl0_ctrl_reg.mirror(status, UVM_CHECK, UVM_BACKDOOR);//后门访问获取reg值
- rgm.chnl1_ctrl_reg.mirror(status, UVM_CHECK, UVM_BACKDOOR);//比较所有读写值
- rgm.chnl2_ctrl_reg.mirror(status, UVM_CHECK, UVM_BACKDOOR);
- // send IDLE command
- `uvm_do_on(idle_reg_seq, p_sequencer.reg_sqr)
- endtask
- task do_formatter();
- `uvm_do_on_with(fmt_config_seq, p_sequencer.fmt_sqr, {fifo inside {SHORT_FIFO, ULTRA_FIFO}; bandwidth inside {LOW_WIDTH, ULTRA_WIDTH};})
- endtask
- task do_data();
- fork
- `uvm_do_on_with(chnl_data_seq, p_sequencer.chnl_sqrs[0],
- {ntrans inside {[400:600]}; ch_id==0; data_nidles inside {[0:3]}; pkt_nidles inside {1,2,4,8}; data_size inside {8,16,32};})
- `uvm_do_on_with(chnl_data_seq, p_sequencer.chnl_sqrs[1],
- {ntrans inside {[400:600]}; ch_id==0; data_nidles inside {[0:3]}; pkt_nidles inside {1,2,4,8}; data_size inside {8,16,32};})
- `uvm_do_on_with(chnl_data_seq, p_sequencer.chnl_sqrs[2],
- {ntrans inside {[400:600]}; ch_id==0; data_nidles inside {[0:3]}; pkt_nidles inside {1,2,4,8}; data_size inside {8,16,32};})
- join
- #10us; // wait until all data haven been transfered through MCDF
- endtask
- endclass: mcdf_full_random_virtual_sequence
用到的三个内建序列 -uvm_reg_hw_reset_seq -uvm_reg_bit_bash_seq -uvm_reg_access_seq
先复习一下例码,在body中例化对应序列后,将rgm给到序列的model,然后调用序列的start(参数是m_sequencer,应该是说对应的user自己的寄存器sequencer)
- class mcdf_example_seq extends uvm_reg_sequence;
- mcdf_rgm rgm;
- `uvm_object_utils()
- `uvm_declare_p_sequencer()
- ...
- task body();
- uvm_status_e status;
- uvm_reg_data_t data;
- uvm_reg_hw_reset_seq reg_rst_seq=new();
- uvm_reg_bit_bash_seq reg_bit_bas_seq=new();
- uvm_reg_access_seq reg_acc_seq=new();
- if(!uvm_config_db#(mcdf_rgm)::get(null, get_full_name(), "rgm", rgm)) begin
- `uvm_error() end
- @(negedge p_sequencer.vif.rstn);
- @(posedge p_sequencer.vif.rstn);
- `uvm_info()
- reg_rst_seq.model=rgm;
- reg_rst_seq.start(m_sequencer);
- `uvm_info()
- `uvm_info()
- reg_bit_bash_seq.model=rgm;
- reg_bit_bash_seq.start(m_sequencer);
- `uvm_info()
- `uvm_info()
- reg_acc_seq.model=rgm;
- reg_acc_seq.start(m_sequencer);
- `uvm_info()
- endtask
- endclass
实验5代码如下
- class mcdf_reg_builtin_virtual_sequence extends mcdf_base_virtual_sequence;
- `uvm_object_utils(mcdf_reg_builtin_virtual_sequence)
- function new (string name = "mcdf_reg_builtin_virtual_sequence");
- super.new(name);
- endfunction
-
- task do_reg();//这里是do_reg不是body?回头复习整理时查查
- uvm_reg_hw_reset_seq reg_rst_seq = new(); //一样的先例化内建序列
- uvm_reg_bit_bash_seq reg_bit_bash_seq = new();
- uvm_reg_access_seq reg_acc_seq = new();
-
- // 等待复位信号
- @(negedge p_sequencer.intf.rstn);
- @(posedge p_sequencer.intf.rstn);
-
- `uvm_info("BLTINSEQ", "register reset sequence started", UVM_LOW)
- rgm.reset();//先调用reset
- reg_rst_seq.model = rgm;
- reg_rst_seq.start(p_sequencer.reg_sqr);//这里的参数是p_sequencer的reg_sqr?
- `uvm_info("BLTINSEQ", "register reset sequence finished", UVM_LOW)
-
- `uvm_info("BLTINSEQ", "register bit bash sequence started", UVM_LOW)
- // 在执行下个序列前先复位
- p_sequencer.intf.rstn <= 'b0;
- repeat(5) @(posedge p_sequencer.intf.clk);
- p_sequencer.intf.rstn <= 'b1;
-
- rgm.reset();
- reg_bit_bash_seq.model = rgm;
- reg_bit_bash_seq.start(p_sequencer.reg_sqr);
- `uvm_info("BLTINSEQ", "register bit bash sequence finished", UVM_LOW)
-
- `uvm_info("BLTINSEQ", "register access sequence started", UVM_LOW)
- p_sequencer.intf.rstn <= 'b0;
- repeat(5) @(posedge p_sequencer.intf.clk);
- p_sequencer.intf.rstn <= 'b1;
- rgm.reset();
- reg_acc_seq.model = rgm;
- reg_acc_seq.start(p_sequencer.reg_sqr);
- `uvm_info("BLTINSEQ", "register access sequence finished", UVM_LOW)
- endtask
- endclass: mcdf_reg_builtin_virtual_sequence