ahbl_tran:
声明protected是保证只有当前的class以及子类可以访问这个变量,外部调用没法改变变量值
声明locol 子类也没法改变
`ifndef AHBL_TRAN_SV
`define AHBL_TRAN_SV
class ahbl_tran extends uvm_sequence_item;
rand logic [31:0] haddr = 32'h0;
rand logic [31:0] hdata = 32'h0;
rand logic htrans_t htran = NSEQ;
rand logic hburst_t hburst = SINGLE;
rand logic hsize_t hsize = BYTE;
rand logic [3:0] hprot = 4'b0;
rand logic hsel = 1'b0;
rand logic hreadyout = 1'b1;
rand logic hwrite = 1'b0;
rand logic hresp = 1'b0;
protected rand int unsigned bst_beats;//一组传输需要的传输次数
protected rand logic [5:0] haddr_q[$]; //一组传输中的地址队列集合
protected rand logic [31:0] hrwdata_q[$];//数据集合
protected rand htrans_t htrans_q[$];//传输状态集合
protected int unsigned haddr_idx = 0;//用于driver调用函数的计数
protected int unsigned hrwdata_idx = 0;
protected int unsigned htrans_idx = 0;
`uvm_object_utils_begin(ahbl_tran)
`uvm_field_int (hsel, UVM_DEFAULT)
`uvm_field_int (haddr, UVM_DEFAULT)
`uvm_field_enum (htrans_t,htrans, UVM_DEFAULT)
`uvm_field_enum (hsize_t,hsize, UVM_DEFAULT)
`uvm_field_enum (hburst_t,hburst, UVM_DEFAULT)
`uvm_field_int (hprot, UVM_DEFAULT)
`uvm_field_int (hwrite, UVM_DEFAULT)
`uvm_field_int (hrwdata, UVM_DEFAULT)
`uvm_field_int (hresp, UVM_DEFAULT)
`uvm_field_int (hreadyout, UVM_DEFAULT)
`uvm_field_int (bst_beats, UVM_DEFAULT)
`uvm_field_queue_int (haddr_q, UVM_DEFAULT)
`uvm_field_queue_int (hrwdata_q, UVM_DEFAULT)
`uvm_field_queue_enum (htrans_t,htrans_q, UVM_DEFAULT)
`uvm_field_int (haddr_idx, UVM_DEFAULT)
`uvm_field_int (hrwdata_idx, UVM_DEFAULT)
`uvm_field_int (htrans_idx, UVM_DEFAULT)
`uvm_object_utils_end
constraint haddr_constr{
{hsize == HWORD} -> {haddr[0] == 1'b0};
{hsize == WORD} -> {haddr[1:0] == 2'b0};
solve hsize before haddr;
}
constraint htrans_constr{
{htrans == IDLE} -> {hburst == SINGLE};
solve htrans before haddr;
}
constraint hburst_constr{
(hburst == SINGLE) -> (bst_beats == 1);
(hburst == WRAP4) -> (bst_beats == 4);
(hburst == WRAP8) -> (bst_beats == 8);
(hburst == WRAP16) -> (bst_beats == 16);
(hburst == INCR4) -> (bst_beats == 4);
(hburst == INCR8) -> (bst_beats == 8);
(hburst == INCR16) -> (bst_beats == 16);
solve hburst before bst_beats;
}
constraint queue_constr{
haddr_q.size() == bst_beats;//传输的次数作为三个队列的大小
hrwdata_q.size() == bst_beats;
htrans_q.size() == bst_beats;
solve bst_beats before haddr_q;
solve bst_beats before hrwdata_q;
solve bst_beats before htrans_q;
}
function new(string name = "ahbl_tran");
super.new(name);
hsel = 1'b0;
haddr = 32'h0;
htrans = NSEQ;
hsize = BYTE;
hburst = SINGLE;
hprot = 4'h0;
hwrite = 32'h0;
hresp = 1'b0;
hreadyout = 1'b1;
haddr_idx = 0;
hrwdata_idx = 0;
htrans_idx = 0;
endfunction
function void post_randomize();//在randomize之后自动运行
int i;
haddr_q[0] = haddr;//刚randomize的数据作为第一个数据
htrans_q[0] = NSEQ;//第一个数据为NSEQ
hrwdata_q[0] = hrwdata;
for(i=1;i
ahbl_drv:
定义两个空的pkt_dataphase、pkt_addrphase;
在没有rst情况下,第一次判断dataphase为空,不发送data,然后判断addrphase也为空不发送addr;
addrphase:try_next_item 如果没得到设置初始值重新循环,如果得到addr就发送到总线,并将指针给到dataphase;
则第二次循环判断data不为空,根据hwrite发送数据;然后判断是不是传输结束(hready为0 & SINGLE传输|最后一个数据传输);如果结束item_done、两个pkt置空;如果在burst中间,则继续传输;(相当于对trans中的burst传输数据整体发送)
实现了当前地址和数据相差一拍,以及和下一个地址的交叠操作;
class ahbl_mst_drv extends uvm_driver #(ahbl_tran);
`uvm_component_utils(ahbl_mst_drv)
virtual ahbl_if vif;
protected ahbl_tran pkt_dpha = null;//最开始data phase和adds phase为空
protected ahbl_tran pkt_apha = null;
function new(string name,uvm_component parent);
super.new(name,parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
if(!uvm_config_db#(virtual ahbl_if)::get(this,"","vif",vif))
`uvm_fatal("No vif","vif is not set")
endfunction
task run_phase(uvm_phase phase);
while(1) begin
@(vif.mst_cb);
if(!vif.mst_cb.hresetn)begin//如果reset给初始值
vif.mst_cb.hsel <= 1'b0;
vif.mst_cb.haddr <= 32'b0;
vif.mst_cb.htrans <= 2'b0;
vif.mst_cb.hsize <= 3'b0;
vif.mst_cb.hburst <= 3'b0;
vif.mst_cb.hprot <= 4'b0;
vif.mst_cb.hwrite <= 1'b0;
vif.mst_cb.hwdata <= 32'b0;
end
else begin
if(pkt_dpha != null)begin//不rst 第一次进入dpha为空 不进入 发完第一个addr后进入
drive_1cyc_pkt_dpha(pkt_dpha);
if(vif.mst_cb.hready & ((pkt_dpha.hburst == SINGLE) | pkt_dpha.last_beat()))begin
//判断是不是传输结束(hready为0 & SINGLE传输|最后一个数据传输)
seq_item_port.item_done();
pkt_apha = null;
pkt_dpha = null;
end
end
if(pkt_apha != null)begin//第一次进入apha也为空
drive_1cyc_pkt_apha(pkt_apha);
end
else begin
seq_item_port.try_next_item(pkt_apha);//try 得没得到都返回 get不得到不返回
if(pkt_apha != null)begin//如果得到addr 发一个addr到总线
drive_1cyc_pkt_apha(pkt_apha);
pkt_apha.print();
end
else begin
drive_1cyc_idle();
end
end
end
end
endtask
task drive_1cyc_pkt_dpha(ref ahbl_tran t);
if(vif.mst_cb.hready)begin
vif.mst_cb.hwdata <= t.hwrite ? t.nxt_hrwdata():32'd0;
end
endtask
task drive_1cyc_pkt_apha(ref ahbl_tran t);//传递地址以及控制信号
if(vif.mst_cb.hready)begin
vif.mst_cb.hsel <= t.hsel;
vif.mst_cb.haddr <= ((t.htrans != IDLE) & (t.htrans != BUSY))?t.nxt_haddr() : vif.haddr;
vif.mst_cb.htrans <= t.nxt_htrans();
vif.mst_cb.hsize <= t.hsize;
vif.mst_cb.hburst <= t.hburst;
vif.mst_cb.hprot <= t.hprot;
vif.mst_cb.hwrite <= t.hwrite;
this.pkt_dpha = this.pkt_apha; //发出去一个addr后将t给到pkt_dpha
end
endtask
task drive_1cyc_idle();
vif.mst_cb.hsel <= 1'b0;
vif.mst_cb.haddr <= 32'd0;
vif.mst_cb.htrans <= IDLE;
vif.mst_cb.hsize <= BYTE;
vif.mst_cb.hburst <= SINGLE;
vif.mst_cb.hprot <= 4'h0;
vif.mst_cb.hwrite <= 1'b0;
endtask
endclass
ahbl_mon:
定义一个 pkt;如果rst则pkt置空;
判断slv来的ready,只有ready为高才表示信号真正有效 如果无效重新while循环判断;
如果ready为高,判断如果pkt里不是空的就把总线上的data送出去,并将pkt置空。(本质就是判断apha有没有接收到信号)
然后如果 hsel 为高说明选中了这个模块 & htrans[1]为1 即NONSEQ=2'b10 SEQ=2'b11传输状态时,就把addr phase的各个信号采样到pkt里。
则第二次循环 pkt 不为空,就判断读写 在data phase中把数据送到scb;
(与drv区别:drv将burst传输看作整体发送,需要判断SINGLE以及是否是最后一位传输;
mon将burst传输过来的数据拆分一个一个传递到scb中,方便之后的比较,因为apb
只支持单个传输。)
class ahbl_mst_mon extends uvm_monitor;
`uvm_component_utils(ahbl_mst_mon)
virtual ahbl_if vif;
uvm_analysis_port #(ahbl_tran) ap;
ahbl_tran pkt;
function new(string name,uvm_component parent);
super.new(name,parent);
ap = new("ap",this);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
if(!uvm_config_db#(virtual ahbl_if)::get(this,"","vif",vif))
`uvm_fatal("No vif","vif is not set!")
endfunction
virtual task run_phase(uvm_phase phase);
while(1)begin
@(vif.mon_cb)
if(!vif.mon_cb.hresetn)begin
pkt = null;
end
else begin
//只有ready为高才表示信号真正有效 如果无效重新while循环
if(vif.mon_cb.hready)begin
//ready为高,如果pkt里不是空的把总线上的data送出去,并pkt置空
//本质就是判断apha有没有接收到
if(pkt != null)begin
samp_dpha(pkt);
ap.write(pkt);
pkt = null;
end
if(vif.mon_cb.hsel & vif.mon_cb.htrans[1])begin
//hsel为高选中了这个模块 & htrans[1]为1 即NONSEQ=2'b10 SEQ=2'b11状态时
samp_apha(pkt);//就把addr phase采样到pkt里
end
end
end
end
endtask
virtual task samp_dpha(ref ahbl_tran pkt);
pkt.hrwdata = pkt.hwrite ? vif.mon_cb.hwdata : vif.mon_cb.hrdata;
pkt.hresp = vif.mon_cb.hresp;
endtask
virtual task samp_apha(ref ahbl_tran pkt);
pkt = ahbl_tran::type_id::create("pkt");
pkt.hsel = vif.mon_cb.hsel;
pkt.haddr = vif.mon_cb.haddr;
pkt.htrans = htrans_t'(vif.mon_cb.htrans);//强制类型转换成枚举类型
pkt.hsize = hsize_t'(vif.mon_cb.hsize);
pkt.hburst = hburst_t'(vif.mon_cb.hburst);
pkt.hprot = vif.mon_cb.hprot;
pkt.hwrite = vif.mon_cb.hwrite;
endtask
endclass
mst_agt:
class ahbl_mst_agt extends uvm_agent;
`uvm_component_utils(ahbl_mst_agt)
ahbl_mst_drv drv_i;
ahbl_mst_sqr sqr_i;
ahbl_mst_mon mon_i;
virtual ahbl_if vif;
function new(string name,uvm_component parent);
super.new(name,parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
if(!uvm_config_db#(virtual ahbl_if)::get(this,"","vif",vif))
`uvm_fatal("No vif","vif is not set!")
mon_i = ahbl_mst_mon::type_id::create("mon_i",this);
uvm_config_db#(virtual ahbl_if)::set(this,"mon_i","vif",vif);
if(!(uvm_config_db#(uvm_active_passive_enum)::get(this,"","is_active",is_active)))
`uvm_fatal("is_active","is_active is not set!")
if(is_active == UVM_ACTIVE)begin
sqr_i = ahbl_mst_sqr::type_id::create("sqr_i",this);
drv_i = ahbl_mst_drv::type_id::create("drv_i",this);
uvm_config_db#(virtual ahbl_if)::set(this,"drv_i","vif",vif);
end
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
if(is_active == UVM_ACTIVE)begin
drv_i.seq_item_port.connect(sqr_i.seq_item_export);
end
endfunction
endclass