[UVM] How to read and write registers without using RAL Model?

              Register Access without RAL Model

 

       In this section will see an example that shows one of the ways to access DUT registers without 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.

  • table of Contents

         一、Below is the block diagram of DMA.

二、Below are the DMA registers,

三、Below is the testbench block diagram,

3.1、The testbench component DMA agent is used to access the reg_interface.

3.2、In testbench,

四、Base Sequence

五、Write Sequence

六、Read Sequence

七、Register Accessing

7.1、Write Operation:

7.2、Read Operation:

7.3、Register address defines

7.4、Write and Read operation using defines

八、Accessing registers from TestCase


一、Below is the block diagram of DMA.

           

二、Below are the DMA registers,

  • IN
  • CTRL
  • IO ADDR
  • MEM ADDR

    Address of each register and register field description is given below,

 

三、Below is the testbench block diagram,

          

 

3.1、The testbench component DMA agent is used to access the reg_interface.

    DMA Agent consists of,

  • Driver
  • Monitor
  • Sequencer
  • Sequences (Write sequence and Read Sequence)

3.2、In testbench,

  • Write to the register is done by calling the write sequence
  • Read of the register is done by calling the read sequence

    This testbench is UVM based testbench. For ease understanding, only the sequence and test case is explained in this section. For detailed steps on writing UVM Testbench refer to UVM Testbench Architecture.

 

四、Base Sequence

class dma_sequence extends uvm_sequence#(dma_seq_item);
   
  `uvm_object_utils(dma_sequence)
   
  //---------------------------------------
  //Constructor
  //---------------------------------------
  function new(string name = "dma_sequence");
    super.new(name);
  endfunction
   
  `uvm_declare_p_sequencer(dma_sequencer)
   
  //---------------------------------------
  // create, randomize and send the item to driver
  //---------------------------------------
  virtual task body();
   repeat(2) begin
    req = dma_seq_item::type_id::create("req");
    wait_for_grant();
    req.randomize();
    send_request(req);
    wait_for_item_done();
   end
  endtask
endclass

五、Write Sequence

class write_sequence extends uvm_sequence#(dma_seq_item);
  bit [31:0] t_addr,t_data;
   
  `uvm_object_utils(write_sequence)
    
  //---------------------------------------
  //Constructor
  //---------------------------------------
  function new(string name = "write_sequence");
    super.new(name);
  endfunction
   
  virtual task body();
    `uvm_do_with(req,{req.wr_en==1;req.addr==t_addr;req.wdata==t_data;})
  endtask
endclass

六、Read Sequence

class read_sequence extends uvm_sequence#(dma_seq_item);
  bit [31:0] t_addr;
   
  `uvm_object_utils(read_sequence)
    
  //---------------------------------------
  //Constructor
  //---------------------------------------
  function new(string name = "read_sequence");
    super.new(name);
  endfunction
   
  virtual task body();
    `uvm_do_with(req,{req.wr_en==0;req.addr==t_addr;})
  endtask
endclass

七、Register Accessing

       Write or Read operation to any SFR is done by calling the write or read sequence respectively.

7.1、Write Operation:

//Write to register INTR
wr_seq.t_addr = 32'h400;
wr_seq.t_data = 32'hFFFF_0F0F;
wr_seq.start(env.dma_agnt.sequencer);
 
//Write to register CTRL
wr_seq.t_addr = 32'h404;
wr_seq.t_data = 32'h1234_5678;
wr_seq.start(env.dma_agnt.sequencer);
 
//Write to register IO_ADDR
wr_seq.t_addr = 32'h408;
wr_seq.t_data = 32'hABCD_EF12;
wr_seq.start(env.dma_agnt.sequencer);
 
//Write to register MEM_ADDR
wr_seq.t_addr = 32'h40C;
wr_seq.t_data = 32'h9731_2345;
wr_seq.start(env.dma_agnt.sequencer);

7.2、Read Operation:

//Read from register INTR
rd_seq.t_addr = 32'h400;
rd_seq.start(env.dma_agnt.sequencer);
 
//Read from register CTRL
rd_seq.t_addr = 32'h404;
rd_seq.start(env.dma_agnt.sequencer);
 
//Read from register IO_ADDR
rd_seq.t_addr = 32'h408;
rd_seq.start(env.dma_agnt.sequencer);
 
//Read from register MEM_ADDR
rd_seq.t_addr = 32'h40C;
rd_seq.start(env.dma_agnt.sequencer); 

       In the above code, Register Address is assigned for register access. for the complex designs, the number of registers will be more. readability and debug will be difficult. to overcome this we can use define for register address.

7.3、Register address defines

`define INTR_SFR_ADDR     32'h400
`define CTRL_SFR_ADDR     32'h404
`define IO_ADDR_SFR_ADDR  32'h408
`define MEM_ADDR_SFR_ADDR 32'h40C

7.4、Write and Read operation using defines

  • WRITE OPERATION
wr_seq.t_addr = `INTR_SFR_ADDR;
wr_seq.t_data = 32'hFFFF_0F0F;
wr_seq.start(env.dma_agnt.sequencer);
 
wr_seq.t_addr = `CTRL_SFR_ADDR;
wr_seq.t_data = 32'h1234_5678;
wr_seq.start(env.dma_agnt.sequencer);
 
wr_seq.t_addr = `IO_ADDR_SFR_ADDR;
wr_seq.t_data = 32'hABCD_EF12;
wr_seq.start(env.dma_agnt.sequencer);
 
wr_seq.t_addr = `MEM_ADDR_SFR_ADDR;
wr_seq.t_data = 32'h9731_2345;
wr_seq.start(env.dma_agnt.sequencer);
  • READ OPERATION
rd_seq.t_addr = `INTR_SFR_ADDR;
rd_seq.start(env.dma_agnt.sequencer);
 
rd_seq.t_addr = `CTRL_SFR_ADDR;
rd_seq.start(env.dma_agnt.sequencer);
 
rd_seq.t_addr = `IO_ADDR_SFR_ADDR;
rd_seq.start(env.dma_agnt.sequencer);
 
rd_seq.t_addr = `MEM_ADDR_SFR_ADDR;
rd_seq.start(env.dma_agnt.sequencer); 

八、Accessing registers from TestCase

class dma_reg_test extends uvm_test;
 
  `uvm_component_utils(dma_reg_test)
   
  //---------------------------------------
  // env instance
  //---------------------------------------
  dma_model_env env;
   
  //---------------------------------------
  // sequence instance
  //---------------------------------------
  write_sequence wr_seq;
  read_sequence  rd_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 env
    env = dma_model_env::type_id::create("env", this);
     
    // Create the sequence
    wr_seq = write_sequence::type_id::create("wr_seq");
    rd_seq = read_sequence::type_id::create("rd_seq");
  endfunction : build_phase
 
  //---------------------------------------
  // end_of_elobaration phase
  //--------------------------------------- 
  virtual function void end_of_elaboration();
    //print's the topology
    print();
  endfunction
   
  //---------------------------------------
  // run_phase - starting the test
  //---------------------------------------
  task run_phase(uvm_phase phase);   
    phase.raise_objection(this);
     
    wr_seq.t_addr = `INTR_SFR_ADDR;
    wr_seq.t_data = 32'hFFFF_0F0F;
    wr_seq.start(env.dma_agnt.sequencer);
     
    wr_seq.t_addr = `CTRL_SFR_ADDR;
    wr_seq.t_data = 32'h1234_5678;
    wr_seq.start(env.dma_agnt.sequencer);
     
    wr_seq.t_addr = `IO_ADDR_SFR_ADDR;
    wr_seq.t_data = 32'hABCD_EF12;
    wr_seq.start(env.dma_agnt.sequencer);
     
    wr_seq.t_addr = `MEM_ADDR_SFR_ADDR;
    wr_seq.t_data = 32'h9731_2345;
    wr_seq.start(env.dma_agnt.sequencer);
 
    rd_seq.t_addr = `INTR_SFR_ADDR;
    rd_seq.start(env.dma_agnt.sequencer);
     
    rd_seq.t_addr = `CTRL_SFR_ADDR;
    rd_seq.start(env.dma_agnt.sequencer);
     
    rd_seq.t_addr = `IO_ADDR_SFR_ADDR;
    rd_seq.start(env.dma_agnt.sequencer);
     
    rd_seq.t_addr = `MEM_ADDR_SFR_ADDR;
    rd_seq.start(env.dma_agnt.sequencer);   
    phase.drop_objection(this);
  endtask : run_phase
   
endclass : dma_reg_test
  • Simulator output
UVM_INFO @ 0: reporter [RNTST] Running test dma_reg_test…
—————————————————————-
Name Type Size Value
—————————————————————-
uvm_test_top dma_reg_test – @1881
 env dma_model_env – @1949
 dma_agnt dma_agent – @2017
 driver dma_driver – @2128
 rsp_port uvm_analysis_port – @2200
 seq_item_port uvm_seq_item_pull_port – @2163
 monitor dma_monitor – @2048
 item_collected_port uvm_analysis_port – @2095
 sequencer dma_sequencer – @2231
 rsp_export uvm_analysis_export – @2276
 seq_item_export uvm_seq_item_pull_imp – @2686
 arbitration_queue array 0 – 
 lock_queue array 0 – 
 num_last_reqs integral 32 ‘d1 
 num_last_rsps integral 32 ‘d1 
—————————————————————-
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_objection.svh(1271) @ 195: reporter [TEST_DONE] 
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_report_server.svh(847) @ 195: reporter 
— UVM Report Summary —

** Report counts by severity
UVM_INFO : 3
UVM_WARNING : 0
UVM_ERROR : 0
UVM_FATAL : 0
** Report counts by id
[RNTST] 1
[TEST_DONE] 1
[UVM/RELNOTES] 1 

 

Published 208 original articles · Like 150 · Visits 50,000+

Guess you like

Origin blog.csdn.net/gsjthxy/article/details/105465029