目录
1.1移除driver中的mailbox句柄和do_drive()中用mailbox句柄通信的方式,用driver自带的seq_item_port通信;定义对应的uvm_sequencer
1.2将generator中发送trans的任务改为底层sequence。将mcdf_base_test中的idle_reg()和write_reg()和read_reg()提取改为seq
1.3在agent中声明、例化sequencer,并TLM连接到driver
1.4去掉generator在mcdf_base_test中的声明+例化+连接到driver
1.7连接virtual sequencer和底层sequencer的句柄
1.9将原本test中产生和发送trans的任务提取到mcdf_data_consistence_basic_virtual_sequence中
实验目标
存在问题
主要是关于sequence和sequencer的,见之前的笔记,没有太多改变。
实验任务
1.1移除driver中的mailbox句柄和do_drive()中用mailbox句柄通信的方式,用driver自带的seq_item_port通信;定义对应的uvm_sequencer
首先是去掉mailbox的定义
class chnl_driver extends uvm_driver #(chnl_trans);
local virtual chnl_intf intf;
// mailbox #(chnl_trans) req_mb;
// mailbox #(chnl_trans) rsp_mb;
在do_drive()中将原来用mailbox通信的方式改为PORT通信。通过driver的seq_item_port端口调用get_next_item(req)获取req,由sequence的函数set_sequence_id设置id,所用id为req这个item调用get_sequence_id得到的;最后返回rsp。
task do_drive();
chnl_trans req, rsp;
@(posedge intf.rstn);
forever begin
// this.req_mb.get(req);
this.chnl_write(req);
void'($cast(rsp, req.clone()));
rsp.rsp = 1;
// this.rsp_mb.put(rsp);
end
endtask
task do_drive();
chnl_trans req, rsp;
@(posedge intf.rstn);
forever begin
//TODO-1.1 Use seq_item_port to get request item
seq_item_port.get_next_item(req);
this.chnl_write(req);
void'($cast(rsp, req.clone()));
rsp.rsp = 1;
//TODO-1.1 Use seq_item_port to put response item
rsp.set_sequence_id(req.get_sequence_id());
seq_item_port.item_done(rsp);
end
endtask
定义sequencer,只需要注册和new函数即可,注意是参数类的要加参数#()
class chnl_sequencer extends uvm_sequencer #(chnl_trans);
`uvm_component_utils(chnl_sequencer)
function new (string name = "chnl_sequencer", uvm_component parent);
super.new(name, parent);
endfunction
endclass: chnl_sequencer
在fmt_pkg和reg_pkg中的操作完全相同。
1.2将generator中发送trans的任务改为底层sequence。将mcdf_base_test中的idle_reg()和write_reg()和read_reg()提取改为seq
改造generator:不需要mailbox;由于变成sequence,start任务变成body()任务;将原来assert with做随机化约束变成`uvm_do_with;将mailbox通信改为seq通信;注意也是个参数类#()
class chnl_data_sequence extends uvm_sequence #(chnl_trans);
rand int pkt_id = 0;
rand int ch_id = -1;
rand int data_nidles = -1;
rand int pkt_nidles = -1;
rand int data_size = -1;
rand int ntrans = 10;
`uvm_object_utils_begin(chnl_data_sequence)
`uvm_field_int(pkt_id, UVM_ALL_ON)
`uvm_field_int(ch_id, UVM_ALL_ON)
`uvm_field_int(data_nidles, UVM_ALL_ON)
`uvm_field_int(pkt_nidles, UVM_ALL_ON)
`uvm_field_int(data_size, UVM_ALL_ON)
`uvm_field_int(ntrans, UVM_ALL_ON)
`uvm_object_utils_end
`uvm_declare_p_sequencer(chnl_sequencer)
function new (string name = "chnl_data_sequence");
super.new(name);
endfunction
task body();
repeat(ntrans) send_trans();
endtask
task send_trans();
chnl_trans req, rsp;
`uvm_do_with(req, {local::ch_id >= 0 -> ch_id == local::ch_id;
local::pkt_id >= 0 -> pkt_id == local::pkt_id;
local::data_nidles >= 0 -> data_nidles == local::data_nidles;
local::pkt_nidles >= 0 -> pkt_nidles == local::pkt_nidles;
local::data_size >0 -> data.size() == local::data_size;
})
this.pkt_id++;
`uvm_info(get_type_name(), req.sprint(), UVM_HIGH)
get_response(rsp);
`uvm_info(get_type_name(), rsp.sprint(), UVM_HIGH)
assert(rsp.rsp)
else $error("[RSPERR] %0t error response received!", $time);
endtask
function void post_randomize();
string s;
s = {s, "AFTER RANDOMIZATION \n"};
s = {s, "=======================================\n"};
s = {s, "chnl_data_sequence object content is as below: \n"};
s = {s, super.sprint()};
s = {s, "=======================================\n"};
`uvm_info(get_type_name(), s, UVM_HIGH)
endfunction
endclass: chnl_data_sequence
在fmt_pkg和reg_pkg中的操作完全相同。
//原来在mcdf_base_test中的三个虚任务
virtual task idle_reg();
void'(reg_gen.randomize() with {cmd == `IDLE; addr == 0; data == 0;});
reg_gen.start();
endtask
virtual task write_reg(bit[7:0] addr, bit[31:0] data);
void'(reg_gen.randomize() with {cmd == `WRITE; addr == local::addr; data == local::data;});
reg_gen.start();
endtask
virtual task read_reg(bit[7:0] addr, output bit[31:0] data);
void'(reg_gen.randomize() with {cmd == `READ; addr == local::addr;});
reg_gen.start();
data = reg_gen.data;
endtask
//被替换成reg_pkg中的三个sequence,分别做约束,注册恶,new函数
class idle_reg_sequence extends reg_base_sequence;
constraint cstr{
addr == 0;
cmd == `IDLE;
data == 0;
}
`uvm_object_utils(idle_reg_sequence)
function new (string name = "idle_reg_sequence");
super.new(name);
endfunction
endclass: idle_reg_sequence
class write_reg_sequence extends reg_base_sequence;
constraint cstr{
cmd == `WRITE;
}
`uvm_object_utils(write_reg_sequence)
function new (string name = "write_reg_sequence");
super.new(name);
endfunction
endclass: write_reg_sequence
class read_reg_sequence extends reg_base_sequence;
constraint cstr{
cmd == `READ;
}
`uvm_object_utils(read_reg_sequence)
function new (string name = "read_reg_sequence");
super.new(name);
endfunction
endclass: read_reg_sequence
1.3在agent中声明、例化sequencer,并TLM连接到driver
class chnl_agent extends uvm_agent;
chnl_driver driver;
chnl_monitor monitor;
//声明sequencer
chnl_sequencer sequencer;
local virtual chnl_intf vif;
`uvm_component_utils(chnl_agent)
function new(string name = "chnl_agent", uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
driver = chnl_driver::type_id::create("driver", this);
monitor = chnl_monitor::type_id::create("monitor", this);
//例化sequencer
sequencer = chnl_sequencer::type_id::create("sequencer", this);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
//连接driver和sequencer
driver.seq_item_port.connect(sequencer.seq_item_export);
endfunction
function void set_interface(virtual chnl_intf vif);
this.vif = vif;
driver.set_interface(vif);
monitor.set_interface(vif);
endfunction
endclass: chnl_agent
在fmt_pkg和reg_pkg中的操作完全相同。
1.4去掉generator在mcdf_base_test中的声明+例化+连接到driver
1.5去掉1.2中已经提取为seq的三个task
1.6实现MCDF顶层的virtual sequencer
virtual sequencer包含所有底层sequencer的句柄
class mcdf_virtual_sequencer extends uvm_sequencer;
reg_sequencer reg_sqr;
fmt_sequencer fmt_sqr;
chnl_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
1.7连接virtual sequencer和底层sequencer的句柄
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;
`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);
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);
//和底层的sequencer连接起来
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;
endfunction
endclass: mcdf_env
1.8将所有发送序列的顺序和组织等内容移植到mcdf_base_virtual_sequence,需要将mcdf_base_test::run_phase()发送序列的功能移植到mcdf_base_virtual_sequence;mcdf_base_test::run_phase()只需要挂载对应的顶层sequence
就是对应virtual sequencer的顶层virtual sequence。
class mcdf_base_virtual_sequence extends uvm_sequence;
//对应virtual sequencer的顶层virtual 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;
`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)
this.do_reg();
this.do_formatter();
this.do_data();
`uvm_info(get_type_name(), "=====================FINISHED=====================", UVM_LOW)
endtask
// do register configuration
virtual task do_reg();
endtask
// do external formatter down stream slave configuration
virtual task do_formatter();
endtask
// do data transition from 3 channel slaves
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
而在mcdf_base_test::run_phase()中只需要运行对应的虚方法
task run_phase(uvm_phase phase);
phase.raise_objection(this);
this.run_top_virtual_sequence();
phase.drop_objection(this);
endtask
virtual task run_top_virtual_sequence();
endtask
在不同的test中用继承的字方法来自定义所需要的的seq
task run_top_virtual_sequence();
mcdf_data_consistence_basic_virtual_sequence top_seq = new();
top_seq.start(env.virt_sqr);
endtask
task run_top_virtual_sequence();
mcdf_full_random_virtual_sequence top_seq = new();
top_seq.start(env.virt_sqr);
endtask
1.9将原本test中产生和发送trans的任务提取到mcdf_data_consistence_basic_virtual_sequence中
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;
// 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;})
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;
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;
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
原本在test中的处理trans的三个任务早已在1.2中被提取为sequence(idle_reg_seq,write_reg_seq,read_reg_seq )
现在的test只剩下注册,new函数,运行顶层virtual seq的任务了
class mcdf_data_consistence_basic_test extends mcdf_base_test;
`uvm_component_utils(mcdf_data_consistence_basic_test)
function new(string name = "mcdf_data_consistence_basic_test", uvm_component parent);
super.new(name, parent);
endfunction
task run_top_virtual_sequence();
mcdf_data_consistence_basic_virtual_sequence top_seq = new();
top_seq.start(env.virt_sqr);
endtask
endclass: mcdf_data_consistence_basic_test