目录
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的,见之前的笔记,没有太多改变。
首先是去掉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中的操作完全相同。
改造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
- 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中的操作完全相同。
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
- 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
就是对应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
- 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