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_endconstraint 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;//第一个数据为NSEQhrwdata_q[0] = hrwdata;for(i=1;i<bst_beats;i++)begin//根据每次传输的size进行地址位移 //1byte8位地址加1 2byte16位地址加2 4byte32位地址加4 haddr_q[i] = haddr_q[i-1] + (2**hsize);htrans_q[i]= SEQ;//后续数据为SEQendendfunctionvirtual function logic [31:0] nxt_haddr();//定义的函数driver使用haddr_idx++;return haddr_q[haddr_idx-1];endfunctionvirtual function logic [31:0] nxt_hrwdata();hrwdata_idx++;return hrwdata_q[hrwdata_idx-1];endfunctionvirtual function logic [31:0] nxt_htrans();htrans_idx++;return htrans_q[htrans_idx-1];endfunctionvirtual function bit last_beat();return (htrans_idx == htrans_q.size());endfunctionvirtual function int get_bst_beats();return (bst_beats);endfunctionendclass `endif//AHBL_TRAN_SV
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);endfunctionfunction 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")endfunctiontask 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;endelse beginif(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;endendif(pkt_apha != null)begin//第一次进入apha也为空drive_1cyc_pkt_apha(pkt_apha);endelse beginseq_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();endelse begindrive_1cyc_idle();endendendendendtasktask drive_1cyc_pkt_dpha(ref ahbl_tran t);if(vif.mst_cb.hready)beginvif.mst_cb.hwdata <= t.hwrite ? t.nxt_hrwdata():32'd0;endendtasktask drive_1cyc_pkt_apha(ref ahbl_tran t);//传递地址以及控制信号if(vif.mst_cb.hready)beginvif.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_dphaendendtasktask 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;endtaskendclass
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);endfunctionfunction 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!")endfunctionvirtual task run_phase(uvm_phase phase);while(1)begin@(vif.mon_cb)if(!vif.mon_cb.hresetn)begin pkt = null;endelse begin//只有ready为高才表示信号真正有效 如果无效重新while循环if(vif.mon_cb.hready)begin//ready为高,如果pkt里不是空的把总线上的data送出去,并pkt置空//本质就是判断apha有没有接收到if(pkt != null)beginsamp_dpha(pkt);ap.write(pkt);pkt = null;endif(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里endendendendendtaskvirtual 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;endtaskvirtual 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);endfunctionfunction 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)beginsqr_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);endendfunctionfunction void connect_phase(uvm_phase phase);super.connect_phase(phase);if(is_active == UVM_ACTIVE)begindrv_i.seq_item_port.connect(sqr_i.seq_item_export);endendfunction
endclass