-------------------------------------建立vip的sequence_lib
base_sequence:
`ifndef LVC_AHB_BASE_SEQUENCE_SV
`define LVC_AHB_BASE_SEQUENCE_SV
class lvc_ahb_base_sequence extends uvm_sequence #(lvc_ahb_transaction);
`uvm_object_utils(lvc_ahb_base_sequence)
function new(string name="");
super.new(name);
endfunction : new
endclass : lvc_ahb_base_sequence
`endif
master_single_trans:添加body()发送req 接收rsp
`ifndef LVC_AHB_MASTER_SINGLE_TRANS_SV
`define LVC_AHB_MASTER_SINGLE_TRANS_SV
class lvc_ahb_master_single_trans extends lvc_ahb_base_sequence;
rand bit [`LVC_AHB_MAX_ADDR_WIDTH-1:0] addr;//地址和数据
rand bit [`LVC_AHB_MAX_DATA_WIDTH-1:0] data;
rand xact_type_enum xact;//Read还是Write
rand burst_size_enum bsize;
constraint single_trans_cstr {
xact inside {READ, WRITE};
}
`uvm_object_utils(lvc_ahb_master_single_trans)
function new(string name="");
super.new(name);
endfunction : new
virtual task body();
`uvm_info(get_type_name(),"Starting sequence", UVM_HIGH)
`uvm_do_with(req, {//发送数据
addr == local::addr;
data.size() == 1;
data[0] == local::data;
burst_size == bsize;
burst_type == SINGLE;
xact_type == xact;
})
get_response(rsp);//req rsp预定义了 是lvc_ahb_transaction类型
if(xact == READ)
data = rsp.data[0];//如果是read就从rsp的data[0]拿出数据
`uvm_info(get_type_name(),$psprintf("Done sequence: %s",req.convert2string()), UVM_HIGH)
endtask: body
endclass : lvc_ahb_master_single_trans
`endif
都放入sequence_lib:然后更新ahb_pkg
`ifndef LVC_AHB_SEQUENCE_LIB_SVH
`define LVC_AHB_SEQUENCE_LIB_SVH
`include "lvc_ahb_base_sequence.sv"
`include "lvc_ahb_master_single_trans.sv"
`endif
---------------------------------------在顶层seq_lib下建立elem_seqs文件夹(搭建激励的架子)
rkv_ahbram_single_write_seq里面将底层vip的master_single_trans例化其中,通过·uvm_do_on_with通过Virtual seqr(p_sequencer)挂载到vip的master_sqr上!
rkv_ahbram_single_write_seq:
`ifndef RKV_AHBRAM_SINGLE_WRITE_SEQ_SV
`define RKV_AHBRAM_SINGLE_WRITE_SEQ_SV
class rkv_ahbram_single_write_seq extends rkv_ahbram_base_element_sequence;
rand bit [31:0] addr;
rand bit [31:0] data;
rand burst_size_enum bsize;
constraint single_write_cstr {
soft addr[1:0] == 0;
soft bsize == BURST_SIZE_32BIT;
}
`uvm_object_utils(rkv_ahbram_single_write_seq)
function new (string name = "rkv_ahbram_single_write_seq");
super.new(name);
endfunction
virtual task body();
lvc_ahb_master_single_trans ahb_single;
`uvm_info("body", "Entered...", UVM_LOW)
`uvm_do_on_with(ahb_single, p_sequencer.ahb_mst_sqr, //p_sequencer已经在base_element_sequence中声明
{addr == local::addr; data == local::data; xact == WRITE; bsize == local::bsize;}
)
`uvm_info("body", "Exiting...", UVM_LOW)
endtask
endclass
`endif // RKV_AHBRAM_SINGLE_WRITE_SEQ_SV
rkv_ahbram_single_read_seq:取消body中给入data、加了一个从lvc_ahb_master_single_trans拿出rsp中data的操作
`ifndef RKV_AHBRAM_SINGLE_READ_SEQ_SV
`define RKV_AHBRAM_SINGLE_READ_SEQ_SV
class rkv_ahbram_single_read_seq extends rkv_ahbram_base_element_sequence;
rand bit [31:0] addr;
rand bit [31:0] data;
rand burst_size_enum bsize;
constraint single_read_cstr {
soft addr[1:0] == 0;
soft bsize == BURST_SIZE_32BIT;
}
`uvm_object_utils(rkv_ahbram_single_read_seq)
function new (string name = "rkv_ahbram_single_read_seq");
super.new(name);
endfunction
virtual task body();
lvc_ahb_master_single_trans ahb_single;
`uvm_info("body", "Entered...", UVM_LOW)
`uvm_do_on_with(ahb_single, p_sequencer.ahb_mst_sqr,
{addr == local::addr; xact == READ; bsize == local::bsize;}
)
data = ahb_single.data;//从例化的ahb_single里把data拿出来,在其中 data = rsp.data[0]
`uvm_info("body", "Exiting...", UVM_LOW)
endtask
endclass
`endif // RKV_AHBRAM_SINGLE_read_SEQ_SV
在virtual seq中声明刚才建立的seq:
// element sequence declartion
rkv_ahbram_single_write_seq single_write;
rkv_ahbram_single_read_seq single_read;
然后再smoke_virt_seq里就可以使用:在其中设定了随机数addr和data的限定,和single_write、single_read的操作以及最后的compare_data(wr_val, rd_val)比对;
`ifndef RKV_AHBRAM_SMOKE_VIRT_SEQ_SV
`define RKV_AHBRAM_SMOKE_VIRT_SEQ_SV
class rkv_ahbram_smoke_virt_seq extends rkv_ahbram_base_virtual_sequence;
`uvm_object_utils(rkv_ahbram_smoke_virt_seq)
function new (string name = "rkv_ahbram_smoke_virt_seq");
super.new(name);
endfunction
virtual task body();
bit [31:0] addr, data;
super.body();
`uvm_info("body", "Entered...", UVM_LOW)
for(int i=0; i<10; i++) begin
std::randomize(addr) with {addr[1:0] == 0; addr inside {['h1000:'h1FFF]};};
std::randomize(wr_val) with {wr_val == (i << 4) + i;};
data = wr_val;
`uvm_do_with(single_write, {addr == local::addr; data == local::data;})
//`uvm_do_with(single_write, {addr == local::addr; data == 'hff;})
`uvm_do_with(single_read, {addr == local::addr; })
rd_val = single_read.data;
compare_data(wr_val, rd_val);
end
`uvm_info("body", "Exiting...", UVM_LOW)
endtask
endclass
`endif
仿真后发现问题应该在rst结束后再发送激励:在顶层rkv_ahbram_virtual_sequence中添加
wait_ready_for_stim();
task wait_cycles(int n = 1);
repeat(n) @(posedge vif.clk);
endtask
task wait_ready_for_stim();
wait_reset_signal_released();
wait_cycles(10);
endtask
debug优化了底层ahb_master_driver:发送数据的同时给定下一个状态(否则多占一拍):
virtual task do_init_read(REQ t);
wait_for_bus_grant();
@(vif.cb_mst);
vif.cb_mst.htrans <= NSEQ;
vif.cb_mst.haddr <= t.addr;
vif.cb_mst.hburst <= t.burst_type;
vif.cb_mst.hsize <= t.burst_size;
vif.cb_mst.hwrite <= 1'b0;
@(vif.cb_mst);
if(t.burst_type == SINGLE) begin
_do_drive_idle();
end
// check ready with delay in current cycle
forever begin
@(negedge vif.hclk);
if(vif.hready === 1'b1) begin
break;
end
else
@(vif.cb_mst);
end
t.data = new[t.current_data_beat_num+1](t.data);
t.data[0] = vif.hrdata;
// update current trans status
t.trans_type = NSEQ;
t.current_data_beat_num = 0; // start beat from 0 to make consistence with data array index
t.all_beat_response[t.current_data_beat_num] = response_type_enum'(vif.hresp);
endtask
最后发现在clone操作时由于transaction没有进行域的自动化导致克隆失败:
ahb_transaction:
`uvm_object_utils_begin(lvc_ahb_transaction)
`uvm_field_array_int(data, UVM_ALL_ON)
`uvm_field_int(addr, UVM_ALL_ON)
`uvm_field_enum(burst_size_enum, burst_size, UVM_ALL_ON)
`uvm_field_enum(burst_type_enum, burst_type, UVM_ALL_ON)
`uvm_field_enum(xact_type_enum, xact_type, UVM_ALL_ON)
`uvm_field_enum(response_type_enum, response_type, UVM_ALL_ON)
`uvm_field_enum(trans_type_enum, trans_type, UVM_ALL_ON)
`uvm_field_array_enum(response_type_enum, all_beat_response, UVM_ALL_ON)
`uvm_field_int(current_data_beat_num, UVM_ALL_ON)
`uvm_field_enum(status_enum, status, UVM_ALL_ON)
`uvm_object_utils_end