[UVM]UVM Register Model應用實例(Example)

                          UVM Register Model Example

       In this section will see an example that shows one of the ways to access DUT registers with the UVM RAL Model.Let’s consider a DMA design which consists of registers in it and reg_interface is used to access the registers.Below is the block diagram of DMA.

  • Table of Contents

一、DMA方塊圖(DMA block diagram)

二、下面是DMA registers定定義

三、測試環境框圖(testbench block diagram)

四、UVM RAL Model創建步驟

4.1、Writing register classes

4.2、Writing register package

4.3、Instantiation of register classes in register package

4.4、Writing Adapter Class

4.5、在env中例化register packet和adapter

4.6、Accessing registers with RAL

4.7、Complete Sequence Code

4.8、Test case


一、DMA方塊圖(DMA block diagram)

                    

 

二、下面是DMA registers定定義

  • INTR
  • CTRL
  • IO_ADDR
  • MEM_ADDR
Register Name Address Field Name MSB LSB   Access skip_reg_test skip_reg_field
INTR 0x3580_0000 mask 31 16 RW    
    status 15 0      
CTRL 0x3580_0004 resvd 31 10 RW    
    io_mem 9 9      
    w_count 8 1      
    start_dma 0 0      
IO_ADDR 0x3580_0008 address 31 0 RW    
MEM_ADDR 0x3580_000C address 31 0 RW    

三、測試環境框圖(testbench block diagram)

     

四、UVM RAL Model創建步驟

  • Writing register classes
  • Writing register package
  • Instantiation of register classes in register package
  • Writing Adapter class
  • Integrating register package and adapter in environment
  • Accessing registers with RAL

 

4.1、Writing register classes

  • 4.1.1、Writing reg class for INTR

4.1.1.1、Register class is written by extending the uvm_reg class

class intr extends uvm_reg;
  `uvm_object_utils(intr)
 
  //---------------------------------------
  // Constructor
  //---------------------------------------  
  function new (string name = "intr");
    super.new(name,32,UVM_NO_COVERAGE); //32 -> Register Width
  endfunction
 
endclass

4.1.1.2、Declare the fields with type uvm_reg_field

//---------------------------------------
// fields instance
//---------------------------------------
rand uvm_reg_field status;
rand uvm_reg_field mask;

4.1.1.3、Create the fields

function void build;  
  // Create bitfield
  status = uvm_reg_field::type_id::create("status");
  mask   = uvm_reg_field::type_id::create("mask");  
endfunction

4.1.1.4、Configure the fields with access type, bit width and etc,

// Create bitfield
status = uvm_reg_field::type_id::create("status");  
// Configure
status.configure(.parent(this),
                 .size(16),
                 .lsb_pos(0),
                 .access("RW"), 
                 .volatile(0),
                 .reset(0),
                 .has_reset(1),
                 .is_rand(1),
                 .individually_accessible(0)
                 );
 
mask = uvm_reg_field::type_id::create("mask");  
mask.configure(.parent(this),
                 .size(16),
                 .lsb_pos(16),
                 .access("RW"), 
                 .volatile(0),
                 .reset(0),
                 .has_reset(1),
                 .is_rand(1),
                 .individually_accessible(0)
                );

4.1.1.5、Complete register class

class intr extends uvm_reg;
  `uvm_object_utils(intr)
    
  //---------------------------------------
  // fields instance
  //---------------------------------------
  rand uvm_reg_field status;
  rand uvm_reg_field mask;
 
  //---------------------------------------
  // Constructor
  //---------------------------------------  
  function new (string name = "intr");
    super.new(name,32,UVM_NO_COVERAGE); //32 -> Register Width
  endfunction
 
  //---------------------------------------
  // build_phase -
  // 1. Create the fields
  // 2. Configure the fields
  //--------------------------------------- 
  function void build;
     
    // Create bitfield
    status = uvm_reg_field::type_id::create("status");  
    // Configure
    status.configure(.parent(this),
                     .size(16),
                     .lsb_pos(0),
                     .access("RW"), 
                     .volatile(0),
                     .reset(0),
                     .has_reset(1),
                     .is_rand(1),
                     .individually_accessible(0));
    // Below line is equivalen to above one  
    // status.configure(this, 32, 0, "RW",   0,        0,        1,        1,      0);
    //reg, bitwidth, lsb, access, volatile, reselVal, hasReset, isRand, fieldAccess
     
    mask = uvm_reg_field::type_id::create("mask");  
    mask.configure(.parent(this),
                     .size(16),
                     .lsb_pos(16),
                     .access("RW"), 
                     .volatile(0),
                     .reset(0),
                     .has_reset(1),
                     .is_rand(1),
                     .individually_accessible(0));   
    endfunction
endclass
  • 4.1.2、Writing reg class for CTRL

  • 4.1.3、Writing reg class for IO_Addr

  • 4.1.4、Writing reg class for Mem_Addr

 

4.2、Writing register package

       register package is written by extending the uvm_reg_block.

class dma_reg_model extends uvm_reg_block;
  `uvm_object_utils(dma_reg_model)
   
  //---------------------------------------
  // Constructor
  //---------------------------------------
  function new (string name = "");
    super.new(name, build_coverage(UVM_NO_COVERAGE));
  endfunction
endclass

 

4.3、Instantiation of register classes in register package

  • Instantiating the register classes
//---------------------------------------
// register instances
//---------------------------------------
rand intr  reg_intr;
rand ctrl  reg_ctrl;
rand io_addr  reg_io_addr;
rand mem_addr reg_mem_addr;
  • Creating, building and configuring the register instances
reg_intr = intr::type_id::create("reg_intr");
reg_intr.build();
reg_intr.configure(this);
 
reg_ctrl = ctrl::type_id::create("reg_ctrl");
reg_ctrl.build();
reg_ctrl.configure(this);
 
reg_io_addr = io_addr::type_id::create("reg_io_addr");
reg_io_addr.build();
reg_io_addr.configure(this);
 
reg_mem_addr = mem_addr::type_id::create("reg_mem_addr");
reg_mem_addr.build();
reg_mem_addr.configure(this);
  • Creating the memory map
default_map = create_map("my_map", 0, 4, UVM_LITTLE_ENDIAN);
  • Adding registers to memory map
default_map.add_reg(reg_intr , 'h0, "RW"); // reg, offset, access
default_map.add_reg(reg_ctrl , 'h4, "RW");
default_map.add_reg(reg_io_addr , 'h8, "RW");
default_map.add_reg(reg_mem_addr, 'hC, "RW");
  • Complete register package class
class dma_reg_model extends uvm_reg_block;
  `uvm_object_utils(dma_reg_model)
   
  //---------------------------------------
  // register instances
  //---------------------------------------
  rand intr  reg_intr;
  rand ctrl  reg_ctrl;
  rand io_addr  reg_io_addr;
  rand mem_addr reg_mem_addr;
   
  //---------------------------------------
  // Constructor
  //---------------------------------------
  function new (string name = "");
    super.new(name, build_coverage(UVM_NO_COVERAGE));
  endfunction
 
  //---------------------------------------
  // Build Phase
  //---------------------------------------
  function void build;
     
    //---------------------------------------
    //reg creation
    //---------------------------------------
    reg_intr = intr::type_id::create("reg_intr");
    reg_intr.build();
    reg_intr.configure(this);
  
    reg_ctrl = ctrl::type_id::create("reg_ctrl");
    reg_ctrl.build();
    reg_ctrl.configure(this);
     
    reg_io_addr = io_addr::type_id::create("reg_io_addr");
    reg_io_addr.build();
    reg_io_addr.configure(this);
   
    reg_mem_addr = mem_addr::type_id::create("reg_mem_addr");
    reg_mem_addr.build();
    reg_mem_addr.configure(this);
     
    //---------------------------------------
    //Memory map creation and reg map to it
    //---------------------------------------
    default_map = create_map("my_map", 0, 4, UVM_LITTLE_ENDIAN);
    default_map.add_reg(reg_intr , 'h0, "RW");  // reg, offset, access
    default_map.add_reg(reg_ctrl , 'h4, "RW");
    default_map.add_reg(reg_io_addr , 'h8, "RW");
    default_map.add_reg(reg_mem_addr, 'hC, "RW");
     
    lock_model();
  endfunction
endclass

4.4、Writing Adapter Class

  • An adapter class is written by extending the uvm_reg_adapter
class dma_adapter extends uvm_reg_adapter;
  `uvm_object_utils (dma_adapter)
 
  //---------------------------------------
  // Constructor
  //---------------------------------------
  function new (string name = "dma_adapter");
      super.new (name);
   endfunction
 
endclass
  • Writing reg2bus method
//---------------------------------------
// reg2bus method
//---------------------------------------
function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw);
  dma_seq_item tx;   
  tx = dma_seq_item::type_id::create("tx");
   
  tx.wr_en = (rw.kind == UVM_WRITE);
  tx.addr  = rw.addr;
  if (tx.wr_en)  tx.wdata = rw.data;
  if (!tx.wr_en) tx.rdata = rw.data;
 
  return tx;
endfunction
  • Writing bus2reg method
//---------------------------------------
// bus2reg method
//---------------------------------------
function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw);
  dma_seq_item tx;
   
  assert( $cast(tx, bus_item) )
    else `uvm_fatal("", "A bad thing has just happened in my_adapter")
 
  rw.kind = tx.wr_en ? UVM_WRITE : UVM_READ;
  rw.addr = tx.addr;
  rw.data = tx.rdata;
   
  rw.status = UVM_IS_OK;
endfunction
  • Complete adapter class
class dma_adapter extends uvm_reg_adapter;
  `uvm_object_utils (dma_adapter)
 
  //---------------------------------------
  // Constructor
  //---------------------------------------
  function new (string name = "dma_adapter");
      super.new (name);
   endfunction
   
  //---------------------------------------
  // reg2bus method
  //---------------------------------------
  function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw);
    dma_seq_item tx;   
    tx = dma_seq_item::type_id::create("tx");
     
    tx.wr_en = (rw.kind == UVM_WRITE);
    tx.addr  = rw.addr;
    if (tx.wr_en)  tx.wdata = rw.data;
    if (!tx.wr_en) tx.rdata = rw.data;
 
    return tx;
  endfunction
 
  //---------------------------------------
  // bus2reg method
  //---------------------------------------
  function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw);
    dma_seq_item tx;
     
    assert( $cast(tx, bus_item) )
      else `uvm_fatal("", "A bad thing has just happened in my_adapter")
 
    rw.kind = tx.wr_en ? UVM_WRITE : UVM_READ;
    rw.addr = tx.addr;
    rw.data = tx.rdata;
 
    rw.status = UVM_IS_OK;
  endfunction
endclass

4.5、在env中例化register packet和adapter

      步驟如下:

  • Instantiating the regmodel and adapter
dma_reg_model  regmodel;  
dma_adapter    m_adapter;
  • Creating the register model and adapter
regmodel = dma_reg_model::type_id::create("regmodel", this);
regmodel.build();
m_adapter = dma_adapter::type_id::create("m_adapter",, get_full_name());
  • Connecting the adapter sequencer with agent sequencer
regmodel.default_map.set_sequencer( .sequencer(dma_agnt.sequencer),
                                    .adapter(m_adapter) );
  • Setting the base address to regmodel address map
regmodel.default_map.set_base_addr('h400);
  • Complete env code
class dma_model_env extends uvm_env;
   
  //---------------------------------------
  // agent and scoreboard instance
  //---------------------------------------
  dma_agent      dma_agnt;
   
  //---------------------------------------
  // Reg Model and Adapter instance
  //--------------------------------------- 
  dma_reg_model  regmodel;  
  dma_adapter    m_adapter;
   
  `uvm_component_utils(dma_model_env)
   
  //---------------------------------------
  // constructor
  //---------------------------------------
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction : new
 
  //---------------------------------------
  // build_phase - create the components
  //---------------------------------------
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    dma_agnt = dma_agent::type_id::create("dma_agnt", this);
     
    //---------------------------------------
    // Register model and adapter creation
    //---------------------------------------
    regmodel = dma_reg_model::type_id::create("regmodel", this);
    regmodel.build();
    m_adapter = dma_adapter::type_id::create("m_adapter",, get_full_name());
  endfunction : build_phase
   
  //---------------------------------------
  // connect_phase - connecting regmodel sequencer and adapter with
  //                             mem agent sequencer and adapter
  //---------------------------------------
  function void connect_phase(uvm_phase phase);
    regmodel.default_map.set_sequencer( .sequencer(dma_agnt.sequencer), .adapter(m_adapter) );
    regmodel.default_map.set_base_addr('h400);       
  endfunction : connect_phase
 
endclass : dma_model_env

4.6、Accessing registers with RAL

4.1.6.1、Write to the register

  • Write to the register is performed by calling the register write method
  • Data to be written to the registers is passed as an argument to the write method
  • SYNTAX:
reg_model.rag_name.write(status, write_data)

4.1.6.2、Read from the register

  • Read from the register is performed by calling the register read method
  • The read method returns the Data
  • SYNTAX:
reg_model.rag_name.read(status, read_data)

4.1.6.3、ACCESS TO THE REGISTERS,

//Write to the Registers
regmodel.reg_intr.write(status, 32'h1234_1234);
regmodel.reg_ctrl.write(status, 32'h1234_5678);
regmodel.reg_io_addr.write(status, 32'h1234_9ABC);
regmodel.reg_mem_addr.write(status, 32'h1234_DEF0);
 
//Read from the register
regmodel.reg_intr.read(status, rdata);
regmodel.reg_ctrl.read(status, rdata);
regmodel.reg_io_addr.read(status, rdata);
regmodel.reg_mem_addr.read(status, rdata);

4.7、Complete Sequence Code

class dma_reg_seq extends uvm_sequence;
 
  `uvm_object_utils(dma_reg_seq)
   
  dma_reg_model regmodel;
   
  //---------------------------------------
  // Constructor
  //---------------------------------------   
  function new (string name = "");
    super.new(name);   
  endfunction
   
  //---------------------------------------
  // Sequence body
  //---------------------------------------     
  task body; 
    uvm_status_e   status;
    uvm_reg_data_t incoming;
    bit [31:0]     rdata;
     
    if (starting_phase != null)
      starting_phase.raise_objection(this);
     
    //Write to the Registers
    regmodel.reg_intr.write(status, 32'h1234_1234);
    regmodel.reg_ctrl.write(status, 32'h1234_5678);
    regmodel.reg_io_addr.write(status, 32'h1234_9ABC);
    regmodel.reg_mem_addr.write(status, 32'h1234_DEF0);
     
    //Read from the registers
    regmodel.reg_intr.read(status, rdata);
    regmodel.reg_ctrl.read(status, rdata);
    regmodel.reg_io_addr.read(status, rdata);
    regmodel.reg_mem_addr.read(status, rdata);
       
    if (starting_phase != null)
      starting_phase.drop_objection(this); 
     
  endtask
endclass

4.8、Test case

       Register sequence is declared, created and started from the test case.

class dma_reg_test extends dma_model_base_test;
 
  `uvm_component_utils(dma_reg_test)
   
  //---------------------------------------
  // sequence instance
  //---------------------------------------
  dma_reg_seq reg_seq;
 
  //---------------------------------------
  // constructor
  //---------------------------------------
  function new(string name = "dma_reg_test",uvm_component parent=null);
    super.new(name,parent);
  endfunction : new
 
  //---------------------------------------
  // build_phase
  //---------------------------------------
  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
 
    // Create the sequence
    reg_seq = dma_reg_seq::type_id::create("reg_seq");
  endfunction : build_phase
   
  //---------------------------------------
  // run_phase - starting the test
  //---------------------------------------
  task run_phase(uvm_phase phase);
     
    phase.raise_objection(this);
      if ( !reg_seq.randomize() ) `uvm_error("", "Randomize failed")
      //Setting sequence in reg_seq
      reg_seq.regmodel       = env.regmodel;
      reg_seq.starting_phase = phase;
      reg_seq.start(env.dma_agnt.sequencer);
    phase.drop_objection(this);
     
    //set a drain-time for the environment if desired
    phase.phase_done.set_drain_time(this, 50);
  endtask : run_phase
   
endclass : dma_reg_test
  • Simulation Output
UVM_INFO @ 0: reporter [RNTST] Running test dma_reg_test…
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_spell_chkr.svh(123) @ 0:
—————————————————————-
Name Type Size Value
—————————————————————-
uvm_test_top dma_reg_test – @1912
 env dma_model_env – @1980
 dma_agnt dma_agent – @2031
 driver dma_driver – @2299
 rsp_port uvm_analysis_port – @2371
 seq_item_port uvm_seq_item_pull_port – @2334
 monitor dma_monitor – @2189
 item_collected_port uvm_analysis_port – @2266
 sequencer dma_sequencer – @2402
 rsp_export uvm_analysis_export – @2447
 seq_item_export uvm_seq_item_pull_imp – @2857
 arbitration_queue array 0 – 
 lock_queue array 0 – 
 num_last_reqs integral 32 ‘d1 
 num_last_rsps integral 32 ‘d1 
—————————————————————-
Design WR addr 400 Data 12341234
Design WR addr 404 Data 12345678
Design WR addr 408 Data 12349abc
Design WR addr 40c Data 1234def0
Design RD addr 400 Data 12341234
Design RD addr 404 Data 12345678
Design RD addr 408 Data 12349abc
Design RD addr 40c Data 1234def0
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_objection.svh(1271) @ 245: reporter [TEST_DONE] 
UVM_INFO dma_test.sv(58) @ 245: uvm_test_top [dma_reg_test] —————————————
UVM_INFO dma_test.sv(59) @ 245: uvm_test_top [dma_reg_test] —- TEST PASS —-
UVM_INFO dma_test.sv(60) @ 245: uvm_test_top [dma_reg_test] —————————————
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_report_server.svh(847) @ 245: reporter [UVM/REPORT/SERVER] 
— UVM Report Summary —

** Report counts by severity
UVM_INFO : 7
UVM_WARNING : 0
UVM_ERROR : 0
UVM_FATAL : 0
** Report counts by id
[RNTST] 1
[TEST_DONE] 1
[UVM/CONFIGDB/SPELLCHK] 1
[UVM/RELNOTES] 1
[dma_reg_test] 3
发布了208 篇原创文章 · 获赞 150 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/gsjthxy/article/details/105451340
今日推荐