Part 1 showed how to create a simple AHB-L agent driver that is capable of driving a single non-sequential access.

Now we'll see how to extend this model to create burst transactions with different sizes and types.

Type definitions


typedef enum bit [1:0] { IDLE, BUSY, NONSEQ, SEQ } e_htrans;
typedef enum bit [2:0] { BYTE, HALF_WORD, WORD, WORD_2, WORD_4, WORD_8, WORD_16, WORD_32} e_hsize;
typedef enum bit [2:0] { SINGLE, INCR, WRAP4, INCR4, WRAP8, INCR8, WRAP16, INCR16 } e_hburst;
typedef enum bit [3:0] { OPCODE_FETCH, DATA_ACCESS, USER_ACCESS, PRIVELEGED, NON_BUFFERABLE, BUFFERABLE, NON_CACHEABLE, CACHEABLE} e_hprot;
typedef enum bit 	   { OKAY, ERROR } e_hresp;

Address Data Object

Since AHB transactions require the master to send an address for all beats in a burst, we can reduce burden on the AHB driver by calculating addresses beforehand when data is randomized. As long as the start address is known along with the size of transfer,t this can be easily calculated. These address data pairs can be stored using an intermediate class as shown below.


class ahb_addr_data extends uvm_object;
  rand bit [31:0] m_addr;
  rand bit [31:0] m_data;
  
  `uvm_object_utils_begin(ahb_addr_data)
  `uvm_field_int 	(m_addr, UVM_PRINT)
  `uvm_field_int 	(m_data, UVM_PRINT)
  `uvm_object_utils_end
  
  function new(string name="ahb_addr_data");
    super.new(name);
  endfunction

Transaction Object

There are a couple of ways to represent bursty transactions in AHB. Since each beat of the burst requires the master to send address along with its data, the master should calculate the next address in each beat of a burst. This calculation can be placed either in the driver or in the transaction packet itself. The driver becomes slightly complicated if it has to calculate the next transaction address before each beat is sent out, and makes it easier to code transaction object. In this case, the start address of the burst can be stored in the transaction object along with an array of only data.

In the second approach shown below, next transaction address is precalculated within the transaction object itself thereby making driver code easier. This also allows an address data pair to be stored and provides a better and complete picture of where each data in the beat should go. Since address calculation depends on a variety of other parameters like hburst and the length, it is best tackled in post_randomize method.


class ahb_pkt extends uvm_sequence_item;  
  function new(string name = "ahb_pkt");
    super.new(name);
  endfunction
  
  rand 	byte unsigned 	m_num_txfr;         // Length of burst for INCR type
  rand  bit[31:0] 		m_start_addr;       // Start address for burst
  rand  e_hburst 		m_hburst;           // Burst type
  rand	bit 			m_hmastlock;
  rand 	e_hprot 		m_hprot;
  rand 	e_hsize 		m_hsize;
  
  rand 	e_htrans 		m_htrans;
  rand 	e_hwrite		m_hwrite;
  rand  ahb_addr_data 	m_addr_data_q[$]; 	
  
  		e_hresp 		m_hresp;
  
  `uvm_object_utils_begin(ahb_pkt)  	
  	`uvm_field_int 	(m_start_addr,	 		UVM_PRINT)
  	`uvm_field_int 	(m_num_txfr,	 		UVM_PRINT|UVM_DEC)
  	`uvm_field_enum (e_hburst, m_hburst, 	UVM_PRINT)
  	`uvm_field_int 	(m_hmastlock, 			UVM_PRINT)
  	`uvm_field_enum (e_hprot, m_hprot, 		UVM_PRINT)
  	`uvm_field_enum (e_hsize, m_hsize, 		UVM_PRINT)
  	`uvm_field_enum (e_htrans, m_htrans, 	UVM_PRINT)
  	`uvm_field_enum (e_hwrite, m_hwrite, 	UVM_PRINT)
  	`uvm_field_enum (e_hresp, m_hresp, 		UVM_PRINT)
  	`uvm_field_queue_object 	(m_addr_data_q, 	UVM_PRINT)
  `uvm_object_utils_end
  
  constraint c_default { 	!(m_htrans inside {SEQ, IDLE, BUSY}); 
                        	m_start_addr % 4 == 0;
                        	soft m_hsize inside {[1:2]} ;
                       }
  
  constraint c_addr_data_q { 
    if (m_hburst == SINGLE)  { m_addr_data_q.size() == 1; m_num_txfr == 1; }
    if (m_hburst == INCR) { m_addr_data_q.size() == m_num_txfr; }
      if (m_hburst == INCR4 || m_hburst == WRAP4) { m_addr_data_q.size() == 4; m_num_txfr == 4; }
        if (m_hburst == INCR8 || m_hburst == WRAP8) { m_addr_data_q.size() == 8; m_num_txfr == 8; }
          if (m_hburst == INCR16 || m_hburst == WRAP16) { m_addr_data_q.size() == 16;  m_num_txfr == 16; }
  }
  
  	function void post_randomize();
    	int l_next_addr = m_start_addr;
    
    	foreach (m_addr_data_q[i]) begin
          
      		m_addr_data_q[i] = ahb_addr_data::type_id::create($sformatf("m_addr_data_q[%0d]", i));
          if (m_hburst inside {INCR, INCR4, INCR8, INCR16}) begin
          		m_addr_data_q[i].randomize() with { m_addr == m_start_addr + i * (2 ** m_hsize); };
          	end
		  	if (m_hburst inside {WRAP4, WRAP8, WRAP16}) begin
            	byte l_hburst;
              	byte l_wrap_bd;
              	case (m_hburst)
                	WRAP4 	: l_hburst = 4;
                	WRAP8 	: l_hburst = 8;
                	WRAP16 	: l_hburst = 16;
              	endcase
              	l_wrap_bd = l_hburst * 2**m_hsize;
              
              `uvm_info(get_type_name(), $sformatf("[post_randomize] %s start=0x%0h next_addr=0x%0h wrap_bd=0x%0h", 
                                                   m_hburst.name(), m_start_addr, l_next_addr, l_wrap_bd), UVM_HIGH)
              if (((l_next_addr % l_wrap_bd) == 0) && (l_next_addr != m_start_addr))
                  l_next_addr = l_next_addr - l_wrap_bd;
              
                  `uvm_info(get_type_name(), $sformatf("[post_randomize] %s start=0x%0h next_addr=0x%0h wrap_bd=0x%0h", 
                                                   m_hburst.name(), m_start_addr, l_next_addr, l_wrap_bd), UVM_HIGH)              
                            
                  m_addr_data_q[i].randomize() with {	m_addr == l_next_addr;  
                                                    };
					l_next_addr = m_addr_data_q[i].m_addr + (2 ** m_hsize);
					`uvm_info(get_type_name(), $sformatf("[post_randomize] %s start=0x%0h next_addr=0x%0h wrap_bd=0x%0h addr=0x%0h", 
                                                         m_hburst.name(), m_start_addr, l_next_addr, l_wrap_bd, m_addr_data_q[i].m_addr), UVM_MEDIUM)              
          	end
    	end
    endfunction
  
  virtual function string convert2string();
    foreach (m_addr_data_q[i]) begin
    	return $sformatf("addr=0x%0h write=0x%0h data=0x%0h",
                         m_addr_data_q[i].m_addr, m_hwrite, m_addr_data_q[i].m_data);
    end
  endfunction
  
endclass

AHB Driver

Each forked thread gets a transaction object that already has all address data pairs in a burst. This makes the driver code much simpler by allowing it to iterate through each address data pair and drive them across the interface. The next thread can only start after the burst is completed by the first thread.


class ahb_driver extends uvm_driver #(ahb_pkt);
  `uvm_component_utils(ahb_driver)
  function new(string name="ahb_driver", uvm_component parent=null);
    super.new(name, parent);
  endfunction
  
  virtual ahb_if 	m_vif;
  ahb_cfg 			m_cfg;
  semaphore 		m_sema4;
  semaphore 		m_sub_sema4;
  
  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
	m_vif = m_cfg.m_ahb_vif;
    m_sema4 = new(1);
    m_sub_sema4 = new(1);
  endfunction
  
  virtual task reset_phase(uvm_phase phase);
    super.reset_phase(phase);
    phase.raise_objection(this);
    m_vif.haddr 	= 0;
    m_vif.hburst 	= 0;
    m_vif.hmastlock = 0;
    m_vif.hprot 	= 0;
    m_vif.hsize 	= 0;
    m_vif.htrans 	= 0;
    m_vif.hwdata  	= 0;
    m_vif.hwrite 	= 0;
   	m_vif.hsel 		= 0;
    phase.drop_objection(this);
  endtask
  
  virtual task main_phase(uvm_phase phase);
    super.main_phase(phase);
    
    fork
      drive_txfr("T1");
      drive_txfr("T2");
    join
  endtask
  
  
  virtual task automatic drive_txfr(string tag);
    forever begin
      m_sema4.get(1);
      	seq_item_port.get_next_item(req);
      	drive_pkt(tag, req);
    	m_sema4.put(1);
		seq_item_port.item_done();
    end
  endtask
  
  virtual task automatic drive_pkt(string tag, REQ l_req);
      foreach (l_req.m_addr_data_q[i]) begin
        m_sub_sema4.get(1);
        `uvm_info(get_type_name(), $sformatf("[drive] %s Iter%0d addr_phase for pkt addr=0x%0h", tag, i, l_req.m_addr_data_q[i].m_addr), UVM_HIGH)
        while (!m_vif.cb.hreadyout) begin
      		@(m_vif.cb);
    	end
        m_vif.haddr 	= l_req.m_addr_data_q[i].m_addr;
        m_vif.hburst 	= l_req.m_hburst;
    	m_vif.hmastlock = l_req.m_hmastlock;
    	m_vif.hprot 	= l_req.m_hprot;
    	m_vif.hsize 	= l_req.m_hsize;
    	m_vif.hwrite 	= req.m_hwrite;
    	m_vif.hsel 		= 1;
        
        if (l_req.m_htrans == NONSEQ) begin
        	if ( i == 0) m_vif.htrans 	= NONSEQ;
       		else         m_vif.htrans 	= SEQ;       
      	end else begin
        	m_vif.htrans = l_req.m_htrans;
        end
        
        do begin
          @(m_vif.cb);          
        end while (! m_vif.cb.hreadyout);               
        
        m_sub_sema4.put(1);
        
        `uvm_info(get_type_name(), $sformatf("[drive] %s Iter%0d data_phase for pkt addr=0x%0h", tag, i, l_req.m_addr_data_q[i].m_addr), UVM_HIGH)     
        if (l_req.m_hwrite) m_vif.hwdata = l_req.m_addr_data_q[i].m_data;
        else 				l_req.m_addr_data_q[i].m_data = m_vif.hrdata;
      end
      m_vif.htrans = IDLE;
  endtask
  
endclass

AHB Sequence

The sequence starts and randomizes an AHB transaction item and waits until item_done is called by the driver.


class ahb_seq extends uvm_sequence;
  `uvm_object_utils(ahb_seq)
  function new(string name = "ahb_seq");
    super.new(name);
  endfunction
  
  int m_loop = 3;
  
  virtual task body();    
    `uvm_info(get_type_name(), $sformatf("Start sequence"), UVM_MEDIUM)
    repeat (m_loop) begin
      	ahb_pkt m_ahb_pkt = ahb_pkt::type_id::create("m_ahb_pkt");
    	start_item(m_ahb_pkt);
      	m_ahb_pkt.randomize();
      	finish_item(m_ahb_pkt);
      	m_ahb_pkt.print();
    end
    #100;
    `uvm_info(get_type_name(), $sformatf("End sequence"), UVM_MEDIUM)
  endtask  
endclass
Output
UVM_INFO @ 0: reporter [RNTST] Running test base_test...
UVM_INFO testbench.sv(313) @ 190: uvm_test_top.m_env.m_ahb_agent.m_seqr@@m_ahb_seq [ahb_seq] Start sequence
---------------------------------------------------------------------------------------------------
Name                           Type           Size  Value                                          
---------------------------------------------------------------------------------------------------
m_ahb_pkt                      ahb_pkt        -     @1935                                          
  m_start_addr                 integral       32    'hf5cb87f8                                     
  m_num_txfr                   integral       8     'd5                                            
  m_hburst                     e_hburst       3     INCR                                           
  m_hmastlock                  integral       1     'h1                                            
  m_hprot                      e_hprot        4     NON_BUFFERABLE                                 
  m_hsize                      e_hsize        3     WORD                                           
  m_htrans                     e_htrans       2     NONSEQ                                         
  m_hwrite                     e_hwrite       1     READ                                           
  m_hresp                      e_hresp        1     OKAY                                           
  m_addr_data_q                da(object)     5     -                                              
    [0]                        ahb_addr_data  -     @2897                                          
      m_addr                   integral       32    'hf5cb87f8                                     
      m_data                   integral       32    'h46df998d                                     
    [1]                        ahb_addr_data  -     @2893                                          
      m_addr                   integral       32    'hf5cb87fc                                     
      m_data                   integral       32    'h46df998d                                     
    [2]                        ahb_addr_data  -     @2896                                          
      m_addr                   integral       32    'hf5cb8800                                     
      m_data                   integral       32    'hb2c28465                                     
    [3]                        ahb_addr_data  -     @2898                                          
      m_addr                   integral       32    'hf5cb8804                                     
      m_data                   integral       32    'hb2c28465                                     
    [4]                        ahb_addr_data  -     @2900                                          
      m_addr                   integral       32    'hf5cb8808                                     
      m_data                   integral       32    'h6d7cd0d                                      
  begin_time                   time           64    190                                            
  end_time                     time           64    450                                            
  depth                        int            32    'd2                                            
  parent sequence (name)       string         9     m_ahb_seq                                      
  parent sequence (full name)  string         47    uvm_test_top.m_env.m_ahb_agent.m_seqr.m_ahb_seq
  sequencer                    string         37    uvm_test_top.m_env.m_ahb_agent.m_seqr          
---------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------
Name                           Type           Size  Value                                          
---------------------------------------------------------------------------------------------------
m_ahb_pkt                      ahb_pkt        -     @3027                                          
  m_start_addr                 integral       32    'hb08a79e0                                     
  m_num_txfr                   integral       8     'd23                                           
  m_hburst                     e_hburst       3     INCR                                           
  m_hmastlock                  integral       1     'h1                                            
  m_hprot                      e_hprot        4     BUFFERABLE                                     
  m_hsize                      e_hsize        3     HALF_WORD                                      
  m_htrans                     e_htrans       2     NONSEQ                                         
  m_hwrite                     e_hwrite       1     WRITE                                          
  m_hresp                      e_hresp        1     OKAY                                           
  m_addr_data_q                da(object)     23    -                                              
    [0]                        ahb_addr_data  -     @2988                                          
      m_addr                   integral       32    'hb08a79e0                                     
      m_data                   integral       32    'h49b8b844                                     
    [1]                        ahb_addr_data  -     @3005                                          
      m_addr                   integral       32    'hb08a79e2                                     
      m_data                   integral       32    'h1932c039                                     
    [2]                        ahb_addr_data  -     @3001                                          
      m_addr                   integral       32    'hb08a79e4                                     
      m_data                   integral       32    'h2205044a                                     
    [3]                        ahb_addr_data  -     @3003                                          
      m_addr                   integral       32    'hb08a79e6                                     
      m_data                   integral       32    'h8bfe5d63                                     
    [4]                        ahb_addr_data  -     @3000                                          
      m_addr                   integral       32    'hb08a79e8                                     
      m_data                   integral       32    'h79eb02a2                                     
    ...                        ...            ...   ...                                            
    [18]                       ahb_addr_data  -     @2971                                          
      m_addr                   integral       32    'hb08a7a04                                     
      m_data                   integral       32    'h2b0451e7                                     
    [19]                       ahb_addr_data  -     @2965                                          
      m_addr                   integral       32    'hb08a7a06                                     
      m_data                   integral       32    'h69125431                                     
    [20]                       ahb_addr_data  -     @2966                                          
      m_addr                   integral       32    'hb08a7a08                                     
      m_data                   integral       32    'hee064b74                                     
    [21]                       ahb_addr_data  -     @2963                                          
      m_addr                   integral       32    'hb08a7a0a                                     
      m_data                   integral       32    'h4584e1e7                                     
    [22]                       ahb_addr_data  -     @2958                                          
      m_addr                   integral       32    'hb08a7a0c                                     
      m_data                   integral       32    'hf5b354af                                     
  begin_time                   time           64    450                                            
  end_time                     time           64    1210                                           
  depth                        int            32    'd2                                            
  parent sequence (name)       string         9     m_ahb_seq                                      
  parent sequence (full name)  string         47    uvm_test_top.m_env.m_ahb_agent.m_seqr.m_ahb_seq
  sequencer                    string         37    uvm_test_top.m_env.m_ahb_agent.m_seqr          
---------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------
Name                           Type           Size  Value                                          
---------------------------------------------------------------------------------------------------
m_ahb_pkt                      ahb_pkt        -     @3115                                          
  m_start_addr                 integral       32    'he5debca0                                     
  m_num_txfr                   integral       8     'd8                                            
  m_hburst                     e_hburst       3     INCR                                           
  m_hmastlock                  integral       1     'h0                                            
  m_hprot                      e_hprot        4     NON_BUFFERABLE                                 
  m_hsize                      e_hsize        3     WORD                                           
  m_htrans                     e_htrans       2     NONSEQ                                         
  m_hwrite                     e_hwrite       1     READ                                           
  m_hresp                      e_hresp        1     OKAY                                           
  m_addr_data_q                da(object)     8     -                                              
    [0]                        ahb_addr_data  -     @3101                                          
      m_addr                   integral       32    'he5debca0                                     
      m_data                   integral       32    'h96ab582d                                     
    [1]                        ahb_addr_data  -     @3100                                          
      m_addr                   integral       32    'he5debca4                                     
      m_data                   integral       32    'h573870a                                      
    [2]                        ahb_addr_data  -     @3091                                          
      m_addr                   integral       32    'he5debca8                                     
      m_data                   integral       32    'h573870a                                      
    [3]                        ahb_addr_data  -     @3083                                          
      m_addr                   integral       32    'he5debcac                                     
      m_data                   integral       32    'hcecccc9d                                     
    [4]                        ahb_addr_data  -     @3097                                          
      m_addr                   integral       32    'he5debcb0                                     
      m_data                   integral       32    'hcecccc9d                                     
    [5]                        ahb_addr_data  -     @3095                                          
      m_addr                   integral       32    'he5debcb4                                     
      m_data                   integral       32    'hcecccc9d                                     
    [6]                        ahb_addr_data  -     @3075                                          
      m_addr                   integral       32    'he5debcb8                                     
      m_data                   integral       32    'hcb203e96                                     
    [7]                        ahb_addr_data  -     @3090                                          
      m_addr                   integral       32    'he5debcbc                                     
      m_data                   integral       32    'h86bc380d                                     
  begin_time                   time           64    1210                                           
  end_time                     time           64    1650                                           
  depth                        int            32    'd2                                            
  parent sequence (name)       string         9     m_ahb_seq                                      
  parent sequence (full name)  string         47    uvm_test_top.m_env.m_ahb_agent.m_seqr.m_ahb_seq
  sequencer                    string         37    uvm_test_top.m_env.m_ahb_agent.m_seqr          
---------------------------------------------------------------------------------------------------
UVM_INFO testbench.sv(329) @ 1750: uvm_test_top.m_env.m_ahb_agent.m_seqr@@m_ahb_seq [ahb_seq] End sequence
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_report_server.svh(847) @ 1750: reporter [UVM/REPORT/SERVER] 
--- UVM Report Summary ---
Did you find what you were looking for?

Quiz

Test Your Knowledge

1 of 5 Score: 0 / 5