更新driver的run_phase以及get_and_drive任务:
task run_phase(uvm_phase phase);
super.run_phase(phase);
fork
get_and_drive();
reset_listener();
join_none
endtask
virtual task get_and_drive();
forever begin
seq_item_port.get_next_item(req);
`uvm_info(get_type_name(), "sequencer got next item", UVM_HIGH)
drive_transfer(req);
void'($cast(rsp, req.clone()));
rsp.set_sequence_id(req.get_sequence_id());
rsp.set_transaction_id(req.get_transaction_id());
seq_item_port.item_done(rsp);
`uvm_info(get_type_name(), "sequencer item_done_triggered", UVM_HIGH)
end
endtask : get_and_drive
virtual task drive_transfer(REQ t);
// TODO implementation in child class 在子类实现
endtask
virtual task reset_listener();
// TODO implementation in child class
endtask
在ahb_if中定义一些enum的debug方便我们后续观察:
response_type_enum debug_hresp;
trans_type_enum debug_htrans;
burst_size_enum debug_hsize;
burst_type_enum debug_hburst;
xact_type_enum debug_xact;
status_enum debug_status;
// debug signals assignment
assign debug_hresp = response_type_enum'(hresp);
assign debug_htrans = trans_type_enum'(htrans);
assign debug_hsize = burst_size_enum'(hsize);
assign debug_hburst = burst_type_enum'(hburst);
// the below signals to be assigned by monitor
// debug_xact ..
// debug_status ..
以及ahb_if 中的时钟块:
clocking cb_mst @(posedge hclk);
// USER: Add clocking block detail
default input #1ps output #1ps;
output haddr, hburst, hbusreq, hlock, hprot, hsize, htrans, hwdata, hwrite;
input hready, hgrant, hrdata;
endclocking : cb_mst
clocking cb_slv @(posedge hclk);
// USER: Add clocking block detail
default input #1ps output #1ps;
input haddr, hburst, hbusreq, hlock, hprot, hsize, htrans, hwdata, hwrite;
output hready, hgrant, hrdata;
endclocking : cb_slv
clocking cb_mon @(posedge hclk);
// USER: Add clocking block detail
default input #1ps output #1ps;
input haddr, hburst, hbusreq, hlock, hprot, hsize, htrans, hwdata, hwrite;
input hready, hgrant, hrdata;
endclocking : cb_mon
子类master_driver:
父类get and drive的drive_transfer在master_driver中实现
先判断传输类型(只有SINGLE),再判断read或write实现对应读写任务
`ifndef LVC_AHB_MASTER_DRIVER_SV
`define LVC_AHB_MASTER_DRIVER_SV
class lvc_ahb_master_driver extends lvc_ahb_driver;
lvc_ahb_agent_configuration cfg;
virtual lvc_ahb_if vif;
`uvm_component_utils(lvc_ahb_master_driver)
function new(string name = "lvc_ahb_master_driver", uvm_component parent = null);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
endfunction
task run_phase(uvm_phase phase);
super.run_phase(phase);
endtask
virtual task drive_transfer(REQ t);
// TODO implementation in child class
case(t.burst_type)
SINGLE: begin do_atomic_trans(t); end
INCR : begin `uvm_error("TYPEERR", "burst type not supported yet") end
WRAP4 : begin `uvm_error("TYPEERR", "burst type not supported yet") end
INCR4 : begin `uvm_error("TYPEERR", "burst type not supported yet") end
WRAP8 : begin `uvm_error("TYPEERR", "burst type not supported yet") end
INCR8 : begin `uvm_error("TYPEERR", "burst type not supported yet") end
WRAP16: begin `uvm_error("TYPEERR", "burst type not supported yet") end
INCR16: begin `uvm_error("TYPEERR", "burst type not supported yet") end
default: begin `uvm_error("TYPEERR", "burst type not defined") end
endcase
endtask
virtual task do_atomic_trans(REQ t);
case(t.trans_type) //??
READ : do_read(t);
WRITE : do_write(t);
IDLE_XACT : begin `uvm_error("TYPEERR", "trans type not supported yet") end
default: begin `uvm_error("TYPEERR", "trans type not defined") end
endcase
endtask
virtual task wait_for_bus_grant();
@(vif.cb_mst iff vif.cb_mst.hgrant === 1'b1);
endtask
virtual task do_write(REQ t);
do_init_write(t);
do_proc_write(t);
endtask
virtual task do_read(REQ t);
do_init_read(t);
do_proc_read(t);
endtask
virtual task do_init_write(REQ t);
wait_for_bus_grant();//等待grant信号
@(vif.cb_mst);
vif.cb_mst.htrans <= NSEQ;//trans_type_enum 类型为NSEQ 代表第一个数据
vif.cb_mst.haddr <= t.addr;
vif.cb_mst.hburst <= t.burst_type;
vif.cb_mst.hsize <= t.burst_size;//固定hsize
vif.cb_mst.hwrite <= 1'b1;//驱动write
@(vif.cb_mst); //传入数据,等待第二拍ready信号为高,
vif.cb_mst.hwdata <= t.data[0];
// check ready with delay in current cycle
forever begin
@(negedge vif.hclk);//需要检测第二拍时的ready,检测下降沿最准确
if(vif.hready === 1'b1) begin
break;
end
else
@(vif.cb_mst);//如果为低则需要再等一拍
end
// 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);
//记录下每一位的response OKAY、ERROR、RETRY、SPLIT
endtask
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);
// check ready with delay in current cycle
forever begin
@(negedge vif.hclk);
if(vif.hready === 1'b1) begin //同样在negedge时检查ready是否为高
break;
end
else
@(vif.cb_mst);
end
t.data = new[t.current_data_beat_num+1](t.data);//重置一下data,new一位并加上之前的data
t.data[0] = vif.hrdata;//等待第二拍ready信号为高,读进数据,
// 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
virtual task do_proc_write(REQ t);
// TODO implement for SEQ operations of other BURST types
do_init_idle(t);
endtask
virtual task do_proc_read(REQ t);
// TODO implement for SEQ operations of other BURST types
do_init_idle(t);
endtask
virtual protected task do_init_idle(REQ t);//写了以后不再写了需要置为IDLE状态
@(vif.cb_mst);
_do_drive_idle();
endtask
virtual protected task _do_drive_idle();
vif.cb_mst.haddr <= 0;
vif.cb_mst.hburst <= 0;
vif.cb_mst.hbusreq <= 0;
vif.cb_mst.hlock <= 0;
vif.cb_mst.hprot <= 0;
vif.cb_mst.hsize <= 0;
vif.cb_mst.htrans <= 0;
vif.cb_mst.hwdata <= 0;
vif.cb_mst.hwrite <= 0;
endtask
virtual protected task reset_listener();
`uvm_info(get_type_name(), "reset_listener ...", UVM_HIGH)
fork
forever begin
@(negedge vif.hresetn); // ASYNC reset
_do_drive_idle();
end
join_none
endtask
endclass
`endif // LVC_AHB_MASTER_DRIVER_SV