I2C学习笔记——00apb_tb、mst_seq_lib、test(env、test_sequence、test)

apb_tb:tb是在dut侧;

        导入tests、if文件;设定周期、复位;例化接口,将接口config_db到uvm_test_top.env.mst和slv中;

`timescale 1ps/1ps
import uvm_pkg::*;
`include "uvm_macros.svh"
`include "lvc_apb_tests.svh"
`include "lvc_apb_if.sv"
module lvc_apb_tb;
  bit clk, rstn;
  initial begin
    fork
      begin 
        forever #5ns clk = !clk;
      end
      begin
        #100ns;
        rstn <= 1'b1;
        #100ns;
        rstn <= 1'b0;
        #100ns;
        rstn <= 1'b1;
      end
    join_none
  end

  lvc_apb_if intf(clk, rstn);

  initial begin
    uvm_config_db#(virtual lvc_apb_if)::set(uvm_root::get(), "uvm_test_top.env.mst", "vif", intf);
    uvm_config_db#(virtual lvc_apb_if)::set(uvm_root::get(), "uvm_test_top.env.slv", "vif", intf);
    run_test("lvc_apb_single_transaction_test");
  end

endmodule

apb_master_seq_lib:        

        base_sequence extends uvm_sequence #(lvc_apb_transfer): new();

        single_write:两个随机变量addr、data和表示状态的trans_status;body()中`uvm_do_with有约束的随机发送→get_response→将rsp返回的状态给trans_status;

        single_read:`uvm_do_with状态改为READ,最后将rsp返回的data给data变量;

        write_read:增加了变量idle_cycles,body()中两个`uvm_do_with;

        burst_write:变量data变成data[ ]数组,软约束随机data的size和值;`uvm_do_with嵌入循环中地址进行移位和发送data;判断rsp返回的状态;

        burst_read:uvm_do_with嵌入循环中地址进行移位,每次返回rsp中的data不断存入data[ ];判断rsp返回的状态;

`ifndef LVC_APB_MASTER_SEQ_LIB_SV
`define LVC_APB_MASTER_SEQ_LIB_SV

//------------------------------------------------------------------------------
// SEQUENCE: default
//------------------------------------------------------------------------------
typedef class lvc_apb_transfer;
typedef class lvc_apb_master_sequencer;

class lvc_apb_master_base_sequence extends uvm_sequence #(lvc_apb_transfer);

  `uvm_object_utils(lvc_apb_master_base_sequence)    
  function new(string name=""); 
    super.new(name);
  endfunction : new

endclass : lvc_apb_master_base_sequence 

// USER: Add your sequences here

class lvc_apb_master_single_write_sequence extends lvc_apb_master_base_sequence;
  rand bit [31:0]      addr;
  rand bit [31:0]      data;
  lvc_apb_trans_status     trans_status;

  `uvm_object_utils(lvc_apb_master_single_write_sequence)    
  function new(string name=""); 
    super.new(name);
  endfunction : new

  virtual task body();
    `uvm_info(get_type_name(),"Starting sequence", UVM_HIGH)
	  `uvm_do_with(req, {trans_kind == WRITE; addr == local::addr; data == local::data;})
    get_response(rsp);
    trans_status = rsp.trans_status;
    `uvm_info(get_type_name(),$psprintf("Done sequence: %s",req.convert2string()), UVM_HIGH)
  endtask: body

endclass: lvc_apb_master_single_write_sequence

class lvc_apb_master_single_read_sequence extends lvc_apb_master_base_sequence;
  rand bit [31:0]      addr;
  rand bit [31:0]      data;
  lvc_apb_trans_status     trans_status;

  `uvm_object_utils(lvc_apb_master_single_read_sequence)    
  function new(string name=""); 
    super.new(name);
  endfunction : new

  virtual task body();
    `uvm_info(get_type_name(),"Starting sequence", UVM_HIGH)
	  `uvm_do_with(req, {trans_kind == READ; addr == local::addr;})
    get_response(rsp);
    trans_status = rsp.trans_status;
    data = rsp.data;
    `uvm_info(get_type_name(),$psprintf("Done sequence: %s",req.convert2string()), UVM_HIGH)
  endtask: body

endclass: lvc_apb_master_single_read_sequence

class lvc_apb_master_write_read_sequence extends lvc_apb_master_base_sequence;
  rand bit [31:0]    addr;
  rand bit [31:0]    data;
  rand int           idle_cycles; 
  lvc_apb_trans_status     trans_status;
  constraint cstr{
    idle_cycles == 0;
  }

  `uvm_object_utils(lvc_apb_master_write_read_sequence)    
  function new(string name=""); 
    super.new(name);
  endfunction : new

  virtual task body();
    `uvm_info(get_type_name(),"Starting sequence", UVM_HIGH)
	  `uvm_do_with(req,  {trans_kind == WRITE; 
                        addr == local::addr; 
                        data == local::data;
                        idle_cycles == local::idle_cycles;
                       })
    get_response(rsp);
    `uvm_do_with(req, {trans_kind == READ; addr == local::addr;})
    get_response(rsp);
    data = rsp.data;
    trans_status = rsp.trans_status;
    `uvm_info(get_type_name(),$psprintf("Done sequence: %s",req.convert2string()), UVM_HIGH)
  endtask: body

endclass: lvc_apb_master_write_read_sequence
  
class lvc_apb_master_burst_write_sequence extends lvc_apb_master_base_sequence;
  rand bit [31:0]      addr;
  rand bit [31:0]      data[];
  lvc_apb_trans_status     trans_status;
  constraint cstr{
    soft data.size() inside {4, 8, 16, 32};
    foreach(data[i]) soft data[i] == addr + (i << 2);
  }

  `uvm_object_utils(lvc_apb_master_burst_write_sequence)    
  function new(string name=""); 
    super.new(name);
  endfunction : new

  virtual task body();
    `uvm_info(get_type_name(),"Starting sequence", UVM_HIGH)
    trans_status = OK;
    foreach(data[i]) begin
	    `uvm_do_with(req, {trans_kind == WRITE; 
                         addr == local::addr + (i<<2); 
                         data == local::data[i];
                         idle_cycles == 0;
                        })
      get_response(rsp);
    end
    `uvm_do_with(req, {trans_kind == IDLE;})
    get_response(rsp);
    trans_status = rsp.trans_status == ERROR ? ERROR : trans_status;
    `uvm_info(get_type_name(),$psprintf("Done sequence: %s",req.convert2string()), UVM_HIGH)
  endtask: body
endclass: lvc_apb_master_burst_write_sequence

class lvc_apb_master_burst_read_sequence extends lvc_apb_master_base_sequence;
  rand bit [31:0]      addr;
  rand bit [31:0]      data[];
  lvc_apb_trans_status     trans_status;
  constraint cstr{
    soft data.size() inside {4, 8, 16, 32};
  }
  `uvm_object_utils(lvc_apb_master_burst_read_sequence)
  function new(string name=""); 
    super.new(name);
  endfunction : new

  virtual task body();
    `uvm_info(get_type_name(),"Starting sequence", UVM_HIGH)
    trans_status = OK;
    foreach(data[i]) begin
	    `uvm_do_with(req, {trans_kind == READ; 
                         addr == local::addr + (i<<2); 
                         idle_cycles == 0;
                        })
      get_response(rsp);
      data[i] = rsp.data;
    end
    `uvm_do_with(req, {trans_kind == IDLE;})
    get_response(rsp);
    trans_status = rsp.trans_status == ERROR ? ERROR : trans_status;
    `uvm_info(get_type_name(),$psprintf("Done sequence: %s",req.convert2string()), UVM_HIGH)
  endtask: body
endclass: lvc_apb_master_burst_read_sequence


`endif // LVC_APB_MASTER_SEQ_LIB_SV

apb_test: 包括apb的env

        apb_env extends uvm_env:例化mst、slv agent,并工厂创建;

        apb_base_test extends uvm_test:例化apb_env、apb_cfg;注册、new();build()中工厂创建cfg,对cfg中控制pready次数、pslverr状态变量赋值,并set到env中,工厂创建env;

        base_test_sequence extends uvm_sequence #(lvc_apb_transfer):定义bit[31:0] mem[bit[31:0]]; 函数check_mem_data是判断给入的addr在mem中有没有数据,有的话数据是不是等于给入的data,没有的话数据是不是等于默认数据;任务wait_reset_release等待一个reset下降沿和上升沿(重置和释放);任务wait_cycles 等待多个时钟周期;函数get_rand_addr 定义32位addr保证[31:12]和[1:0]位为0,其余随机,并返回addr;

        single_transaction_sequence extends apb_base_test_sequence:例化mst中的单读 单写 先写后读的seq;定义控制发生次数的变量test_num;body()中定义32位addr变量,调用base test中任务wait_reset_release、wait_cycles 和 调用get_rand_addr返回一个addr赋值给addr做单写,并存放mem[addr]=addr中;做单读,并判断trans_status为OK后,调用check_mem_data检查mem[addr]中存放的addr数据和读回来的是否相同;和先写后读、写两次立刻读;

        single_transaction_test:例化上一个seq,raise_objection,seq.start(env.mst.sequencer)开始传输将seq挂载到mst.sqr,drop_objection;

        burst_transaction_sequence:例化burst_write_seq、burst_read_seq;定义传输次数;基本等同single_transaction_sequence;

        burst_transaction_test;

`ifndef LVC_APB_TESTS_SV
`define LVC_APB_TESTS_SV

import lvc_apb_pkg::*;

class lvc_apb_env extends uvm_env;
  lvc_apb_master_agent mst;
  lvc_apb_slave_agent slv;
  `uvm_component_utils(lvc_apb_env)
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    mst = lvc_apb_master_agent::type_id::create("mst", this);
    slv = lvc_apb_slave_agent::type_id::create("slv", this);
  endfunction
endclass

class lvc_apb_base_test extends uvm_test;
  lvc_apb_env env;
  lvc_apb_config cfg;
  `uvm_component_utils(lvc_apb_base_test)
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    cfg = lvc_apb_config::type_id::create("cfg");
    // USER TODO
    // Option-1 manually set the config parameters 
    // cfg.slave_pready_default_value = 1;
    // cfg.slave_pready_random = 1;
    // cfg.slave_pslverr_random = 1;
    // Option-2 randomize the config parameters
    // void'(cfg.randomize());
    uvm_config_db#(lvc_apb_config)::set(this,"env.*","cfg", cfg);
    env = lvc_apb_env::type_id::create("env", this);
  endfunction
endclass

class lvc_apb_base_test_sequence extends uvm_sequence #(lvc_apb_transfer);
  bit[31:0] mem[bit[31:0]];
  `uvm_object_utils(lvc_apb_base_test_sequence)
  function new(string name=""); 
    super.new(name);
  endfunction : new
  function bit check_mem_data(bit[31:0] addr, bit[31:0] data);
    if(mem.exists(addr)) begin
      if(data != mem[addr]) begin
        `uvm_error("CMPDATA", $sformatf("addr 32'h%8x, READ DATA expected 32'h%8x != actual 32'h%8x", addr, mem[addr], data))
        return 0;
      end
      else begin
        `uvm_info("CMPDATA", $sformatf("addr 32'h%8x, READ DATA 32'h%8x comparing success!", addr, data), UVM_LOW)
        return 1;
      end
    end
    else begin
      if(data != DEFAULT_READ_VALUE) begin
        `uvm_error("CMPDATA", $sformatf("addr 32'h%8x, READ DATA expected 32'h%8x != actual 32'h%8x", addr, DEFAULT_READ_VALUE, data))
        return 0;
      end
      else begin
        `uvm_info("CMPDATA", $sformatf("addr 32'h%8x, READ DATA 32'h%8x comparing success!", addr, data), UVM_LOW)
        return 1;
      end
    end
  endfunction: check_mem_data

  task wait_reset_release();
    @(negedge lvc_apb_tb.rstn);
    @(posedge lvc_apb_tb.rstn);
  endtask

  task wait_cycles(int n);
    repeat(n) @(posedge lvc_apb_tb.clk);
  endtask

  function bit[31:0] get_rand_addr();
    bit[31:0] addr;
    void'(std::randomize(addr) with {addr[31:12] == 0; addr[1:0] == 0;addr != 0;});
    return addr;
  endfunction
endclass

class lvc_apb_single_transaction_sequence extends lvc_apb_base_test_sequence;
  lvc_apb_master_single_write_sequence single_write_seq;
  lvc_apb_master_single_read_sequence single_read_seq;
  lvc_apb_master_write_read_sequence write_read_seq;
  rand int test_num = 100;
  constraint cstr{
    soft test_num == 100;
  }
  `uvm_object_utils(lvc_apb_single_transaction_sequence)    
  function new(string name=""); 
    super.new(name);
  endfunction : new
  task body();
    bit[31:0] addr;
    this.wait_reset_release();
    this.wait_cycles(10);

    // TEST continous write transaction
    `uvm_info(get_type_name(), "TEST continous write transaction...", UVM_LOW)
    repeat(test_num) begin
      addr = this.get_rand_addr();
      `uvm_do_with(single_write_seq, {addr == local::addr; data == local::addr;})
      mem[addr] = addr;
    end

    // TEST continous read transaction
    `uvm_info(get_type_name(), "TEST continous read transaction...", UVM_LOW)
    repeat(test_num) begin
      addr = this.get_rand_addr();
      `uvm_do_with(single_read_seq, {addr == local::addr;})
      if(single_read_seq.trans_status == OK)
        void'(this.check_mem_data(addr, single_read_seq.data));
    end

    // TEST read transaction after write transaction
    `uvm_info(get_type_name(), "TEST read transaction after write transaction...", UVM_LOW)
    repeat(test_num) begin
      addr = this.get_rand_addr();
      `uvm_do_with(single_write_seq, {addr == local::addr; data == local::addr;})
      mem[addr] = addr;
      `uvm_do_with(single_read_seq, {addr == local::addr;})
      if(single_read_seq.trans_status == OK)
        void'(this.check_mem_data(addr, single_read_seq.data));
    end


    // TEST read transaction immediately after write transaction
    `uvm_info(get_type_name(), "TEST read transaction immediately after write transaction", UVM_LOW)
    repeat(test_num) begin
      addr = this.get_rand_addr();
      `uvm_do_with(write_read_seq, {addr == local::addr; data == local::addr;})
      mem[addr] = addr;
      if(write_read_seq.trans_status == OK)
        void'(this.check_mem_data(addr, write_read_seq.data));
    end

    // TODO
    // TEST write twice and read immediately with burst transaction
    `uvm_info(get_type_name(), "TEST write twice and read immediately with burst transaction...", UVM_LOW)
    repeat(test_num) begin
      addr = this.get_rand_addr();
      // WRITE first time
      `uvm_do_with(req,  {trans_kind == WRITE; 
                    addr == local::addr; 
                    data == local::addr;
                    idle_cycles == 0;
                   })
      mem[addr] = addr;
      get_response(rsp);
      // WRITE second time
      `uvm_do_with(req,  {trans_kind == WRITE; 
                    addr == local::addr; 
                    data == local::addr<<2;
                    idle_cycles == 0;
                   })
      mem[addr] = addr<<2;
      get_response(rsp);
      // READ immediately after WRITE
      `uvm_do_with(req, {trans_kind == READ; addr == local::addr;})
      get_response(rsp);
      if(rsp.trans_status == OK)
      void'(this.check_mem_data(addr, rsp.data));
    end

    this.wait_cycles(10);
  endtask
endclass: lvc_apb_single_transaction_sequence

class lvc_apb_single_transaction_test extends lvc_apb_base_test;
  `uvm_component_utils(lvc_apb_single_transaction_test)
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction
  task run_phase(uvm_phase phase);
    lvc_apb_single_transaction_sequence seq = new();
    phase.raise_objection(this);
    super.run_phase(phase);
    seq.start(env.mst.sequencer);
    phase.drop_objection(this);
  endtask
endclass: lvc_apb_single_transaction_test

class lvc_apb_burst_transaction_sequence extends lvc_apb_base_test_sequence;
  lvc_apb_master_burst_write_sequence burst_write_seq;
  lvc_apb_master_burst_read_sequence burst_read_seq;
  rand int test_num = 100;
  constraint cstr{
    soft test_num == 100;
  }
  `uvm_object_utils(lvc_apb_burst_transaction_sequence)
  function new(string name=""); 
    super.new(name);
  endfunction : new
  task body();
    bit[31:0] addr;
    this.wait_reset_release();
    this.wait_cycles(10);

    // TEST continous write transaction
    repeat(test_num) begin
      addr = this.get_rand_addr();
      `uvm_do_with(burst_write_seq, {addr == local::addr;})
      foreach(burst_write_seq.data[i]) begin
        mem[addr+(i<<2)] = burst_write_seq.data[i];
      end
      `uvm_do_with(burst_read_seq, {addr == local::addr; data.size() == burst_write_seq.data.size();})
      foreach(burst_read_seq.data[i]) begin
        void'(this.check_mem_data(addr+(i<<2), burst_write_seq.data[i]));
      end
    end

    this.wait_cycles(10);
  endtask
endclass: lvc_apb_burst_transaction_sequence

class lvc_apb_burst_transaction_test extends lvc_apb_base_test;
  `uvm_component_utils(lvc_apb_burst_transaction_test)
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction
  task run_phase(uvm_phase phase);
    lvc_apb_burst_transaction_sequence seq = new();
    phase.raise_objection(this);
    super.run_phase(phase);
    seq.start(env.mst.sequencer);
    phase.drop_objection(this);
  endtask
endclass: lvc_apb_burst_transaction_test



`endif // LVC_APB_TESTS_SV

你可能感兴趣的:(学习,笔记)