AXI协议整理

原文出处 http://blog.csdn.net/rill_zhen/article/details/44219593/

总线信号分两种。valid/ready协议 ,

1,valid/ready协议
valid/ready协议
axi协议是典型的基于valid/ready协议的总线协议。
valid/ready协议的优势就是master和slave的相对独立性比较好。
对于一次传输,作为master的发起方不用检查salve是否准备好,就可以将传输内容放到总线上;
同样对于接收方的slave来说,只要可以接收新的数据,就可以将ready信号放到总线上,也不用等待master发起传输。
valid/ready协议可以有效的将master和slave解耦合,也可以有效地减少‘传输握手’的开销。
这和一般的‘request/ack’串行协议不同。比如,AHB,APB,wishbone等片内总线协议。
由于valid/ready协议有上述优势,所以在实际的数字设计时被普遍采用,不仅用于片内总线,各个模块之间的数据交换,也可以采用valid/ready协议。
关于valid/ready协议,有一篇论文可以参考:
EECS150: Interfaces: “FIFO” (a.k.a. Ready/Valid)UC Berkeley College of Engineering
Department of Electrical Engineering and Computer Science

2,乱序
AXI协议是支持乱序传输的协议,也就是说master连续发起了两次传输,对于slave的应答顺序和master的发起顺序可以是不同的。AXI是如何实现乱序传输的呢?有两点非常重要,就是ID和并行。关于ID,我们需要引起足够的重视,在AXI协议的SPEC里面的信号列表里把他放在了第一个,可见这个ID的重要程度。可以这么说,没有ID这个信号,就不能实现乱序。此外,在实际应用中,ID还可以承担除了‘乱序’这一重要任务外,其它重要的任务。比如可以把来自不同CPU的信息放在ID里面等等。。。。。。当然也可以把所有额外的信息放到USER信号来承担,但考虑兼容性,放到ID里面会好一些。

3,并行
关于并行,‘通道分离’是并行能实现的潜在基础。
通道分离,很容易理解,指的是AXI将不仅将读写操作分开了,而且将读写操作用到的信息分成了不同的通道。
写操作分成了3个通道,读操作分成了2个操作。
说到这里,有一点需要提醒一下:从哲学角度来说,读操作和写操作是对称的,是对等的,一写一读,一去一回,没有读哪来写,没有写何必读,就好像太极图里面的一黑一白,多么的和谐与对称。为什么AXI协议里写操作有3个通道,读操作却只有2个通道,这是明目张胆的对读操作的歧视啊!这是为什么呢?
我认为可以从两个角度来解释?
首先,可能和一致性相关。resp通道的一个重要的责任就是解除一致性(WAW,WAR,RAW)(流水线中有三类数据相关冲突:先写后读(RAW)相关;先读后写(WAR)相关;先写后写(WAW)相关),试想如果把读操作的rdata和rresp拆分成两个独立的通道,又有什么奇葩的情景下中会出现后面的写操作还没有得到读操作返回的数据就可以解除一致性呢?!!也就是说即使应读操作的强烈要求,将其也分成3个独立的通道,也不会出现rdata和rresp异步的情况,既然拆分出来的两个通道都是同步的,那么就没有必要拆分了。
其次,可能和哲学有关,读写看似平等,实际上却存在不平等,比如有WAW依赖,却没有RAR依赖,世界本来就是不平等的,你读操作何必一定要和写操作处处平等,把你和写操作拆分开就已经是高看你了,实在不爽的话,就把读写放到一起,就变成了低速,高耦合度,串行,不能乱序的协议啦,比如AHB,APB或者wishbone。
合则串行,分则并行,是合是分,合则慢,分则快,自己选吧。
当然也不是说‘合’就一无是处,‘合’会大大降低信号的数量。
是追求传输速度还是追求信号线数目少,自己选吧。

4,依赖
说完并行,再说依赖。并行和依赖也是一对矛盾。
从大的角度来看,对于读/写,大多数情况下可以认为是并行的,但是读写的地址存在冲突时,读/写又存在依赖。
AW:写地址/控制通道 W:写数据通道 B:写response通道

从小的角度来看,单纯对于写操作,AW、W、B三个通道从形式上看是独立的并行的,但是三个通道在逻辑上又存在一定的依赖。
比如,master的W通道的写数据允不允许比AW通道的写地址先发到总线呢?允许可以,不允许也可以。
如果不允许,W通道的ID信号是否可以去掉不用呢?答案是可以去掉,只要保证去掉之后WDATA发到总线上的顺序和AW通道的数据发到总线上的顺序一致就可以,而这个保证很容易做到。
slave的B通道上的valid允不允许比AW和W通道上的valid早发出去呢?
很显然是不允许的,试想,slave还没有接收完数据就告诉master你接收完了,不出错才怪。
当然,什么事情都不是绝对的,如果在AXI标准协议的基础上再对master和slave增加一些约束,slave的Bvalid也是允许比AW和W两个通道的valid早发出去的,这就是ARM A9中使用的对于写操作的奇葩的‘Early resp’。

5,barrier传输
其实,标准的AXI4里面并没有barrier传输,在ACE协议里面才有,ACE是针对多核系统的一致性总线协议。
但是有时候,单核的系统中对barrier传输的需求也是很迫切的(比如CPU需要和DMA设备同步时),但是有不想全面支持ACE协议,怎么办呢?
可以单纯引入ACE中的‘bar’信号。
对于barrier。需要搞清楚两点即可:
第一,什么是barrier之前的操作,什么是barrier之后的操作;
barrier之前的操作是指,各自通道(AW/AR)上的barrier信号有效之前所发出的操作。barrier之后的操作是指,各自通道上resp(bresp/rresp)返回之后所发出的操作。这里需要注意的是,有一些操作是在‘barrier信号发出之后,resp信号回来之前’发出去的,他们既不属于barrier之前的操作,也不属于barrier之后的操作,属于什么呢?他们就是所谓的‘outstanding 操作’。

第二,memory barrier和synchronization barrier的区别是什么。
关于memory barrier和synchronization barrier,我的理解是:
memory barrier的要求是,以barrier这条命令的resp信号回来为界线(不考虑outstanding的话),保证它后面发的命令能看到前面发的命令的结果即可。
system barrier的要求是,以barrier这条命令的resp信号回来为界线,要保证它前面发出的命令要彻底完成,即不能只被cache下来。
举两个可能的使用场景:
memory barrier:
一个物理CPU(可以多个逻辑核)上面跑了两个线程,其中一个线程(A)更新一个数组,更新完成之后需要告诉另外一个线程(B),线程B读更新之后数组的值。
对于这种场景,线程A更新完数组之后,发一个memory barrier命令就能保证线程B能读到更新后的值。
system barrier:
一个物理CPU(可以多个逻辑核)上面在跑一个线程,这个线程更新一个数组,更新完之后需要告诉VPU,VPU读更新之后的数组的值。
对于这种场景,CPU上面的那个线程更新完数组之后,发一个system barrier命令才能保证VPU读到更新后的值。如果只发一个memory barrier命令,最新的值可能被缓存在L1/L2 cache中,导致VPU读到旧值。

6,小结
总之,AXI是一个很不错的协议,但是在使用过程中要有自己的想法,可以适当做一些变通。
毕竟,协议是ARM定的,但电路是你自己设计的。鞋子合不合脚,只有你知道的最清楚。

7,附录 AXI4 Vs ACE

这里写图片描述

8 个人小体会

  • 协议中讲到, write的response 是针对burst 操作起作用的。 而 read的response是针对于每个tranfer 起作用的。
  • 今天写了一个outstanding的case。列一张时序图
  • 这里写图片描述
    这里就是说,我们每次读/写完成之后,并不会去立刻去 get response,也就是说,可以出现一个burst写没有完成就开始下一个burst 写,一个tranfer 读没完成就开始下一个transfer。(上图是一个操作啊,我认为)

9,还有一种乱序的操作,是基于ID的操作。
这里写图片描述

10, 最后附一个关于outstanding读写的AXI case。
拆分为两个case 是为了不让response 混淆。
但是,同样有个问题:有一个sequence 的读写response 不会混淆吗?
还有个问题read_tran.wait_for_transaction_end();是在干什么?


`ifndef RANDOM_WRITE_READ_SV
`define RANDOM_WRITE_READ_SV
//=======================================================================================//
//====================================== sequence1 ========================================//
`ifndef random_write_read1_SV
`define random_write_read1_SV
class random_write_read1 extends uvm_sequence_item;

  /** rand variable */
  rand bit wr;
  rand bit [31:0] waddr;
  rand bit [31:0] raddr;
  rand bit [127:0] axi_data[16];

  /** UVM Object Utility macro */
  `uvm_object_utils_begin(random_write_read1)
    `uvm_field_int(wr, UVM_ALL_ON)
    `uvm_field_int(waddr, UVM_ALL_ON)
    `uvm_field_int(raddr, UVM_ALL_ON)
    //`uvm_field_queue_int(axi_data, UVM_ALL_ON)
    //`uvm_field_array_int(axi_data, UVM_ALL_ON)
  `uvm_object_utils_end

  function new(string name = "random_write_read1");
    super.new(name);
  endfunction: new

  /** constraint for 4K boundry */
  constraint c_w_addr4k { waddr [11:0] inside {['h000:'hf00]};}
  constraint c_r_addr4k { raddr [11:0] inside {['h000:'hf00]};}

  /** constraint for write and read addr */
  constraint c_w_addr_h {waddr [31:0] inside {['h3000_2000:'h3fff_ffff]};}
  constraint c_r_addr_h {raddr [31:4] inside {['h3000_000:'h3000_1ef]};}
  constraint c_r_addr_l {raddr [3:0] == 'h0;}

endclass 

`endif // random_write_read1_SV
//=======================================================================================//
//class axi_master_rand_outstanding_write_read_sequence1 extends axi_master_base_trans;
//class axi_master_rand_outstanding_write_read_sequence1 extends svt_axi_master_base_sequence;
class axi_master_rand_outstanding_write_read_sequence1 extends axi_master_base_trans ;

  /** Parameter that controls the number of transactions that will be generated */
  int unsigned sequence_length     = 100;
  int unsigned burst_length = 16;
  rand bit[31:0] axi_start_addr     = 32'h0001_0000;

  random_write_read1 rand_wr;

  /** Constrain the sequence length to a reasonable value */
  constraint reasonable_sequence_length {
     sequence_length <= 20000;
  }

  //constraint burst_length_c{
  //  burst_length <= 2000;
  //}

  /** UVM Object Utility macro */
  `uvm_object_utils(axi_master_rand_outstanding_write_read_sequence1)

  /** Class Constructor */
  function new(string name="axi_master_rand_outstanding_write_read_sequence1");
    super.new(name);
  endfunction

  virtual task body();
    svt_axi_master_transaction write_tran, read_tran;
    svt_configuration get_cfg;
    bit status;
    int cnt;
    `uvm_info("body", "Entered ...", UVM_NONE)

    super.body();

    /** Obtain a handle to the port configuration */
    p_sequencer.get_cfg(get_cfg);
    if (!$cast(cfg, get_cfg)) begin
      `uvm_fatal("body", "Unable to $cast the configuration to a svt_axi_port_configuration class");
    end

    fork forever begin
        get_response(rsp);
    end
    join_none

  //--------------------------------------------------------------//
    /***** write default value  for read value check later*/
 for(int i = 0; i < 32; i++) begin
      /** Set up the write transaction */
      `uvm_create(write_tran)
      write_tran.port_cfg     = cfg;
      write_tran.xact_type    = svt_axi_transaction::WRITE;
      write_tran.addr         = 'h3000_0000+256*i;
      write_tran.burst_type   = svt_axi_transaction::INCR;
      write_tran.burst_size   = svt_axi_transaction::BURST_SIZE_128BIT;
      write_tran.atomic_type  = svt_axi_transaction::NORMAL;
      write_tran.burst_length = 16;
      write_tran.data         = new[write_tran.burst_length];
      write_tran.wstrb        = new[write_tran.burst_length];
      write_tran.data_user    = new[write_tran.burst_length];
      foreach (write_tran.data[j]) begin
        write_tran.data[j] ='h3000_0000+256*i+16*j ;
    `uvm_info("body", $sformatf(" writepass, addr is  %0h  , data is  %0h.",write_tran.addr+16*j ,write_tran.data[j]), UVM_NONE);
      end
      foreach(write_tran.wstrb[i]) begin
        write_tran.wstrb[i] = 16'hffff;
      end
      write_tran.wvalid_delay = new[write_tran.burst_length];
      foreach (write_tran.wvalid_delay[i]) begin
        write_tran.wvalid_delay[i]=i;
      end

      /** Send the write transaction */
      `uvm_send(write_tran)

      /** Wait for the write transaction to complete */
    //  get_response(rsp);

      `uvm_info("body", "write default value done", UVM_NONE);
    end


    `uvm_info("body", "Exiting...", UVM_NONE)
  endtask: body
virtual task post_body();
 super.post_body();
  if (`SVT_AXI_TRANSACTION_ADDR_RANGE_NUM_LSB_BITS >12 && `SVT_AXI_TRANSACTION_4K_ADDR_RANGE > 4096) begin 
     `uvm_info("post_body", $sformatf("SVT_AXI_TRANSACTION_ADDR_RANGE_NUM_LSB_BITS is %0d and SVT_AXI_TRANSACTION_4K_ADDR_RANGE is %d  ", `SVT_AXI_TRANSACTION_ADDR_RANGE_NUM_LSB_BITS, `SVT_AXI_TRANSACTION_4K_ADDR_RANGE ), UVM_NONE);

end 
else if (`SVT_AXI_TRANSACTION_ADDR_RANGE_NUM_LSB_BITS  <= 12 && `SVT_AXI_TRANSACTION_4K_ADDR_RANGE <= 4096) begin 
     `uvm_info("post_body", $sformatf("SVT_AXI_TRANSACTION_ADDR_RANGE_NUM_LSB_BITS is %d and SVT_AXI_TRANSACTION_4K_ADDR_RANGE is %d ", `SVT_AXI_TRANSACTION_ADDR_RANGE_NUM_LSB_BITS, `SVT_AXI_TRANSACTION_4K_ADDR_RANGE), UVM_NONE);

end 
else begin 
     `uvm_error ("post_body"," The 4K boundary crossing values are inconsistent");
  end
endtask

endclass: axi_master_rand_outstanding_write_read_sequence1


//=======================================================================================//
//=======================================sequence 2 ======================================//
class random_write_read2 extends uvm_sequence_item;

  /** rand variable */
  rand bit wr;
  rand bit [31:0] waddr;
  rand bit [31:0] raddr;
  rand bit [127:0] axi_data[16];

  /** UVM Object Utility macro */
  `uvm_object_utils_begin(random_write_read2)
    `uvm_field_int(wr, UVM_ALL_ON)
    `uvm_field_int(waddr, UVM_ALL_ON)
    `uvm_field_int(raddr, UVM_ALL_ON)
    //`uvm_field_queue_int(axi_data, UVM_ALL_ON)
    //`uvm_field_array_int(axi_data, UVM_ALL_ON)
  `uvm_object_utils_end

  function new(string name = "random_write_read2");
    super.new(name);
  endfunction: new

  /** constraint for 4K boundry */
  constraint c_w_addr4k { waddr [11:0] inside {['h000:'hf00]};}
  constraint c_r_addr4k { raddr [11:0] inside {['h000:'hf00]};}

  /** constraint for write and read addr */
  constraint c_w_addr_h {waddr [31:0] inside {['h3000_2000:'h3fff_ffff]};}
  constraint c_r_addr_h {raddr [31:4] inside {['h3000_000:'h3000_1ef]};}
  constraint c_r_addr_l {raddr [3:0] == 'h0;}

endclass 

`endif // random_write_read2_SV
//=======================================================================================//
//class axi_master_rand_outstanding_write_read_sequence2 extends axi_master_base_trans;
//class axi_master_rand_outstanding_write_read_sequence2 extends svt_axi_master_base_sequence;
class axi_master_rand_outstanding_write_read_sequence2 extends axi_master_base_trans ;
  /** Parameter that controls the number of transactions that will be generated */
  int unsigned sequence_length     = 100;
  int unsigned burst_length = 16;
  rand bit[31:0] axi_start_addr     = 32'h0001_0000;

  random_write_read2 rand_wr;

  /** Constrain the sequence length to a reasonable value */
  constraint reasonable_sequence_length {
     sequence_length <= 200;
  }

  //constraint burst_length_c{
  //  burst_length <= 2000;
  //}

  /** UVM Object Utility macro */
  `uvm_object_utils(axi_master_rand_outstanding_write_read_sequence2)

  /** Class Constructor */
  function new(string name="axi_master_rand_outstanding_write_read_sequence2");
    super.new(name);
  endfunction

  virtual task body();
    svt_axi_master_transaction write_tran, read_tran;
    svt_configuration get_cfg;
    bit status;
    int cnt;
    `uvm_info("body", "Entered ...", UVM_NONE)

    super.body();

    /** Obtain a handle to the port configuration */
    p_sequencer.get_cfg(get_cfg);
    if (!$cast(cfg, get_cfg)) begin
      `uvm_fatal("body", "Unable to $cast the configuration to a svt_axi_port_configuration class");
    end

    fork forever begin
        get_response(rsp);
    end
    join_none


//--------------------write or read------------//
    //Send 400KByte Pakage Data
    for(int i = 0; i < sequence_length; i++) begin
         //---------------------------------------------------------------//
         /** Set up the write transaction */
          rand_wr = new();
          rand_wr.randomize();
          if(rand_wr.wr == 'b0) begin 
         `uvm_create(write_tran)
         write_tran.port_cfg     = cfg;
         write_tran.xact_type    = svt_axi_transaction::WRITE;
         //write_tran.addr         = axi_addr_4K_boundry(axi_start_addr+16*i*burst_length,burst_length);
         write_tran.addr         = rand_wr.waddr;
         write_tran.burst_type   = svt_axi_transaction::INCR;
         `ifdef USED_MC_WRAPPER
         write_tran.burst_size   = svt_axi_transaction::BURST_SIZE_64BIT;
        `else
         write_tran.burst_size   = svt_axi_transaction::BURST_SIZE_128BIT;
        `endif

         write_tran.atomic_type  = svt_axi_transaction::NORMAL;
         write_tran.burst_length = burst_length;
         //write_tran.burst_length = ajust_axi_burst_length(k,j,sequence_length);
         write_tran.cache_type   = `SVT_AXI_4_AWCACHE_DEVICE_BUFFERABLE;
         write_tran.data         = new[write_tran.burst_length];
         write_tran.wstrb        = new[write_tran.burst_length];
         write_tran.data_user    = new[write_tran.burst_length];

        foreach(write_tran.data[j]) begin
          write_tran.data[i]    = 128'h0000_0000_1111_1111_2222_2222_3333_3333*j;
        `uvm_info(get_type_name(), $sformatf(" WritePass, addr is %0h, data is %0h.", write_tran.addr, write_tran.data[i]),UVM_NONE)
        //uvm_report_info(get_type_name(), $sformatf("Check Value WritePass, addr is %0h, data is %0h.", write_tran.addr, write_tran.data[j]),UVM_NONE)
      end

        foreach(write_tran.wstrb[i]) begin
        `ifdef USED_MC_WRAPPER
            write_tran.wstrb[i] = 'hff;
           `else
                write_tran.wstrb[i] = 'hffff;
           `endif 
      end
         write_tran.wvalid_delay = new[write_tran.burst_length];
         foreach (write_tran.wvalid_delay[i]) begin
           write_tran.wvalid_delay[i]=0;
         end

         /** Send the write transaction */
         `uvm_send(write_tran)

         /** Wait for the write transaction to complete */
         //get_response(rsp);


     for (int i = 0;i <sequence_length;i++) begin 
       write_tran.wait_for_transaction_end();
      `uvm_info("body", "AXI WRITE transaction completed", UVM_NONE);
     end  

//      get_response(rsp);
    `uvm_info("body", "Exiting...", UVM_NONE)
  end
  else begin 
     /** Set up the read transaction */
         `uvm_create(read_tran)
         read_tran.port_cfg     = cfg;
         read_tran.xact_type    = svt_axi_transaction::READ;
         //read_tran.addr         = axi_addr_4K_boundry(axi_start_addr+16*i*burst_length,burst_length);
         read_tran.addr         = rand_wr.raddr;
         read_tran.burst_type   = svt_axi_transaction::INCR;
         `ifdef USED_MC_WRAPPER
            read_tran.burst_size   = svt_axi_transaction::BURST_SIZE_64BIT;
        `else
            read_tran.burst_size   = svt_axi_transaction::BURST_SIZE_128BIT;
        `endif
         read_tran.atomic_type  = svt_axi_transaction::NORMAL;
         read_tran.burst_length = burst_length;
         read_tran.cache_type   = `SVT_AXI_4_ARCACHE_DEVICE_BUFFERABLE;
         read_tran.rresp        = new[read_tran.burst_length];
         read_tran.data         = new[read_tran.burst_length];
         read_tran.rready_delay = new[read_tran.burst_length];
         read_tran.data_user    = new[read_tran.burst_length];
         foreach (read_tran.rready_delay[i]) begin
           read_tran.rready_delay[i]=0;
         end

         /** Send the read transaction */
         `uvm_send(read_tran)

         `uvm_info("body", "AXI READ transaction completed", UVM_NONE);


        `uvm_info("body", "AXI READ transaction completed", UVM_NONE);

    end //for
end
    for (int i = 0;i <sequence_length;i++) begin 
      read_tran.wait_for_transaction_end();
    end  

    // data checker
  foreach(read_tran.data[i])begin
    if(read_tran.data[i] != rand_wr.raddr+16*i )begin
      `uvm_error(get_type_name(), $sformatf(" Debug dmif axi....Check Value Failed, write data is %0h, but read data is %0h.",rand_wr.raddr+16*i,read_tran.data[i]))
      `uvm_info(get_type_name(), $sformatf("Check Value failed "),UVM_NONE)
    end 
    else begin 
      `uvm_info(get_type_name(), $sformatf("Check Value Passed, write data is %0h, and read data is %0h.",rand_wr.raddr+16*i,read_tran.data[i]),UVM_NONE)
    end
  end

    `uvm_info("body", "Exiting...", UVM_NONE)
  endtask: body
virtual task post_body();
 super.post_body();
  if (`SVT_AXI_TRANSACTION_ADDR_RANGE_NUM_LSB_BITS >12 && `SVT_AXI_TRANSACTION_4K_ADDR_RANGE > 4096) begin 
     `uvm_info("post_body", $sformatf("SVT_AXI_TRANSACTION_ADDR_RANGE_NUM_LSB_BITS is %0d and SVT_AXI_TRANSACTION_4K_ADDR_RANGE is %d  ", `SVT_AXI_TRANSACTION_ADDR_RANGE_NUM_LSB_BITS, `SVT_AXI_TRANSACTION_4K_ADDR_RANGE ), UVM_NONE);

end 
else if (`SVT_AXI_TRANSACTION_ADDR_RANGE_NUM_LSB_BITS  <= 12 && `SVT_AXI_TRANSACTION_4K_ADDR_RANGE <= 4096) begin 
     `uvm_info("post_body", $sformatf("SVT_AXI_TRANSACTION_ADDR_RANGE_NUM_LSB_BITS is %d and SVT_AXI_TRANSACTION_4K_ADDR_RANGE is %d ", `SVT_AXI_TRANSACTION_ADDR_RANGE_NUM_LSB_BITS, `SVT_AXI_TRANSACTION_4K_ADDR_RANGE), UVM_NONE);

end 
else begin 
     `uvm_error ("post_body"," The 4K boundary crossing values are inconsistent");
  end
endtask

endclass: axi_master_rand_outstanding_write_read_sequence2
//=======================================================================================//


class dmif_rand_outstanding_write_read_test extends lpddr4_base_test;

    `uvm_component_utils (dmif_rand_outstanding_write_read_test)

    /** Class Constructor */
  function new (string name="dmif_rand_outstanding_write_read_test", uvm_component parent=null);
    super.new (name, parent);
  endfunction : new

  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    i_VRT_dram_config[0].ddrphy_config ='h18;
    i_VRT_dram_config[0].ddrmode = LPDDR4;
    i_VRT_dram_config[0].freq = MEM_FREQ_1600;
    i_VRT_dram_config[0].modmem_lp4_pt=0;
    i_VRT_dram_config[0].m1xclk_hi_period = 625; //313->3200 //625->1600 //938->1066 //417->2400
    i_VRT_dram_config[0].speed_bin_postfix = K;  //don't care, but can't remove
    i_VRT_dram_config[0].freq_dvfsb = MEM_FREQ_1600;//don't care,but can't removei
    i_VRT_dram_config[0].freq_ral = RAL_CONSTR_MEM_FREQ_1600;  
    i_VRT_dram_config[0].freq_dvfsb_ral = RAL_CONSTR_MEM_FREQ_1600;
    i_VRT_dram_config[0].post_randomize();

  endfunction: build_phase

  function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
  endfunction: connect_phase

  task run_phase(uvm_phase phase);
     lpddr4_mc_basic_config_seq m_lpddr4_mc_basic_config_seq;
     //lpddr4_phy_config_1600_cl14_bl16_seq  m_lpddr4_phy_config_1600_cl14_bl16_seq;
     lpddr4_phy_config_MEM1600_bl16_seq m_lpddr4_phy_config_MEM1600_bl16_seq;
     //---------------------------------------------------------------
     //dmif_axi_data_burst_check_seq  m_dmif_axi_data_burst_check_seq; 
     //dmif_axi_random_read_write_check_seq  m_dmif_axi_random_read_write_check_seq;
     axi_master_rand_outstanding_write_read_sequence1 m_axi_master_rand_outstanding_write_read_seq1;
     axi_master_rand_outstanding_write_read_sequence2 m_axi_master_rand_outstanding_write_read_seq2;
     //---------------------------------------------------------------
     lpddr4_cdns_config_seq m_lpddr4_cdns_config_seq;
     lpddr4_cdns_start_seq   m_lpddr4_cdns_start_seq;
     //axi_master_example_sequence        m_axi_master_example_seq;
     virtual dut_monitor_if  dut_monitor_if;
     net_data_t data[];
     int unsigned rdata;
     logic[31:0] data_reg, temp;

     super.run_phase(phase);

    `uvm_info ("main_phase", "Test starting...", UVM_NONE)
    phase.raise_objection(this);
    uvm_config_db#(virtual dut_monitor_if)::get(null, get_full_name(), "dut_vif", dut_monitor_if);

   m_lpddr4_mc_basic_config_seq = lpddr4_mc_basic_config_seq::type_id::create("m_lpddr4_mc_basic_config_seq");
   m_lpddr4_mc_basic_config_seq.start(null);

   #2us;
    //m_lpddr4_phy_config_1600_cl14_bl16_seq = lpddr4_phy_config_1600_cl14_bl16_seq::type_id::create("m_lpddr4_phy_config_1600_cl14_bl16_seq");
    //m_lpddr4_phy_config_1600_cl14_bl16_seq.start(null);
    m_lpddr4_phy_config_MEM1600_bl16_seq = lpddr4_phy_config_MEM1600_bl16_seq::type_id::create("m_lpddr4_phy_config_MEM1600_bl16_seq");
    m_lpddr4_phy_config_MEM1600_bl16_seq.start(null);

    m_lpddr4_cdns_config_seq = lpddr4_cdns_config_seq::type_id::create("m_lpddr4_cdns_config_seq");
    //freq BL RL rddbi
    m_lpddr4_cdns_config_seq.choice_cdns_config("MEM_1600",16,14,0); //choice match configuration
    m_lpddr4_cdns_config_seq.start(null);

    m_lpddr4_cdns_config_seq.adjust_write_timing("MEM_1600",8);
    //**************adjust DFI interface write timing*********************//
    //make sure tphy_wrlat + tphy_wrdata =WL

    //For Performance Eval
    m_lpddr4_cdns_start_seq= lpddr4_cdns_start_seq::type_id::create("m_lpddr4_cdns_start_seq");
    m_lpddr4_cdns_start_seq.start(null);

    fork  
       begin
            wait(dut_monitor_if.command_queue_full == 0);
            disable fork;
        end 
    join


    //m_axi_master_example_seq = axi_master_example_sequence::type_id::create("m_axi_master_example_seq");
    //m_axi_master_example_seq.start(env.virt_sqr.axi0_sqr);

    //-------------------------seq start--------------------------
    //m_dmif_axi_random_read_write_check_seq = dmif_axi_random_read_write_check_seq::type_id::create("m_dmif_axi_random_read_write_check_seq");
    //m_dmif_axi_random_read_write_check_seq.start(env.virt_sqr.axi0_sqr);
    m_axi_master_rand_outstanding_write_read_seq1 = axi_master_rand_outstanding_write_read_sequence1::type_id::create("m_axi_master_rand_outstanding_write_read_seq1");
    m_axi_master_rand_outstanding_write_read_seq2 = axi_master_rand_outstanding_write_read_sequence2::type_id::create("m_axi_master_rand_outstanding_write_read_seq2");
    m_axi_master_rand_outstanding_write_read_seq1.start(env.virt_sqr.axi0_sqr);
    m_axi_master_rand_outstanding_write_read_seq2.start(env.virt_sqr.axi0_sqr);
    //---------------------------seq end--------------------------


    //for(int i=0;i <20;i++)begin
    //    #1us;
    //    env.utb_reg_master.wburst('h3000_0000+32*i, {'h11223344_55667788_99110022_33445566,'haaaabbbb});
    //    #1us;
    //    env.utb_reg_master.rburst('h3000_0000+32*i, 2, data);
    //    $display("READ : addr = %h  , data =  %h  ",32'h3000_0000+32*i,data[0]); 
    //    if(data[0] != 'h11223344_55667788_99110022_33445566)begin
    //        $display("read data not correct,expect %h ",'h11223344_55667788_99110022_33445566); 
    //    end
    //end

    //for(int i=0;i <20;i++)begin
    //    #1us;
    //    env.utb_reg_master.wburst('h3000_0500+32*i,  {'h11223344_55667788_99110022_33445566,'haaaabbbb});
    //    #1us;
    //    env.utb_reg_master.rburst('h3000_0500+32*i, 2, data);
    //    $display("READ : addr = %h  , data =  %h  ",32'h3000_5000+32*i,data[0]); 
    //    if(data[0] != 'h11223344_55667788_99110022_33445566)begin
    //        $display("read data not correct,expect %h ",'h11223344_55667788_99110022_33445566); 
    //    end
    //end

    #5us;
    $display($time," %m: test here");
    phase.drop_objection(this);

  endtask
endclass: dmif_rand_outstanding_write_read_test
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值