AHB-to-APB Bridge——05ahbl_tran、ahlb_drv、ahlb_mon、ahlb_agt

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<bst_beats;i++)begin
			//根据每次传输的size进行地址位移 
			//1byte8位地址加1 2byte16位地址加2 4byte32位地址加4 
		  haddr_q[i] = haddr_q[i-1] + (2**hsize);
		  htrans_q[i]= SEQ;//后续数据为SEQ
    end
  endfunction
  
    virtual function logic [31:0] nxt_haddr();//定义的函数driver使用
		haddr_idx++;
		return haddr_q[haddr_idx-1];
	endfunction

	virtual function logic [31:0] nxt_hrwdata();
		hrwdata_idx++;
		return hrwdata_q[hrwdata_idx-1];
	endfunction

	virtual function logic [31:0] nxt_htrans();
		htrans_idx++;
		return htrans_q[htrans_idx-1];
	endfunction
  
	virtual function bit last_beat();
		return (htrans_idx == htrans_q.size());
	endfunction

	virtual function int get_bst_beats();
		return (bst_beats);
	endfunction

endclass	

`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);
  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

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值