Ready-to-run snippets

Code Examples

Ready-to-run Verilog, SystemVerilog, and UVM examples. Click any to open it live in the IDE.

← All examples

AHB Sequence

UVM

A UVM AHB-Lite master agent with a burst-aware packet whose post_randomize() computes INCR/WRAP addresses per beat, driven by a base test and sequence.

Open in IDE
Related tutorial:
testbench.sv
//---------------------------------------------------------------------------------
// Author 		: Admin, ChipVerify (www.chipverify.com)
// Description 	: AHB-L Master Agent
//---------------------------------------------------------------------------------

`include "uvm_macros.svh"
import uvm_pkg::*;

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;
typedef enum bit 	   { READ, WRITE } e_hwrite;

//---------------------------------------------------------------------------------
// ahb_cfg : Configuration object for AHB agent
//---------------------------------------------------------------------------------
class ahb_cfg extends uvm_object;
  `uvm_object_utils(ahb_cfg)
  function new(string name = "ahb_cfg");
    super.new(name);
  endfunction
  
  virtual ahb_if 	m_ahb_vif;
  bit 				m_vld_val_only;
endclass

//---------------------------------------------------------------------------------
// ahb_addr_data: Small structure to hold address/data pairs
//---------------------------------------------------------------------------------
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
endclass

//---------------------------------------------------------------------------------
// ahb_pkt: AHB transaction packet
//---------------------------------------------------------------------------------
class ahb_pkt extends uvm_sequence_item;  
  function new(string name = "ahb_pkt");
    super.new(name);
  endfunction
  
  rand 	byte unsigned 	m_num_txfr;
  rand  bit[31:0] 		m_start_addr;
  rand  e_hburst 		m_hburst;
  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: AHB Driver
//---------------------------------------------------------------------------------
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_monitor: AHB Monitor
//---------------------------------------------------------------------------------
class ahb_monitor extends uvm_monitor;
  `uvm_component_utils(ahb_monitor)
  function new(string name="ahb_monitor", uvm_component parent=null);
    super.new(name, parent);
  endfunction
  
  ahb_cfg 						m_cfg;
  virtual ahb_if 				m_vif;
  uvm_analysis_port #(ahb_pkt) 	m_analysis_port;
  
  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    m_analysis_port = new("m_analysis_port", this);
    m_vif = m_cfg.m_ahb_vif;
  endfunction

  virtual task main_phase(uvm_phase phase);
    super.main_phase(phase);
    forever begin
      @(m_vif.cb);
    end
  endtask
  
endclass
    
//---------------------------------------------------------------------------------
// ahb_agent : AHB Agent
//---------------------------------------------------------------------------------
class ahb_agent extends uvm_agent;
  `uvm_component_utils(ahb_agent)
  function new(string name="ahb_agent", uvm_component parent=null);
    super.new(name, parent);
  endfunction
  
  ahb_cfg 					m_cfg;
  ahb_driver 	 			m_drv;
  ahb_monitor 	 			m_mon;
  uvm_sequencer #(ahb_pkt) 	m_seqr;
  
  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    
    if (!uvm_config_db#(ahb_cfg)::get(this, "*", "m_ahb_cfg", m_cfg))
      `uvm_fatal(get_type_name(), $sformatf("[CFG] Did not find m_ahb_cfg in config_db"))
    
    if (get_is_active()) begin
      m_drv = ahb_driver::type_id::create("m_drv", this);
      m_seqr = uvm_sequencer#(ahb_pkt)::type_id::create("m_seqr", this);
    end
    
    m_mon = ahb_monitor::type_id::create("m_mon", this);
    
    // Configuration might be needed to build it
    m_drv.m_cfg = m_cfg;
    m_mon.m_cfg = m_cfg;
  endfunction
  
  virtual function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    
    if (get_is_active) begin
      m_drv.seq_item_port.connect(m_seqr.seq_item_export);
    end
  endfunction
endclass

//---------------------------------------------------------------------------------
// ahb_seq : AHB test sequence
//---------------------------------------------------------------------------------
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();
/*      m_ahb_pkt.randomize() with { 	
        							m_hwrite == WRITE; 
                                  	m_hburst == WRAP16; 
                                  	m_start_addr == 32'h34; 
                                  	m_hsize == 2; 
                                 };
*/      
      	finish_item(m_ahb_pkt);
      	m_ahb_pkt.print();
    end
    #100;
    `uvm_info(get_type_name(), $sformatf("End sequence"), UVM_MEDIUM)
  endtask  
endclass

//---------------------------------------------------------------------------------
// base_scoreboard : Base scoreboard to keep tallies
//---------------------------------------------------------------------------------
class base_scoreboard extends uvm_scoreboard;
  `uvm_component_utils(base_scoreboard)
  function new(string name = "base_scoreboard", uvm_component parent=null);
    super.new(name, parent);
  endfunction
  
  uvm_analysis_imp #(ahb_pkt, base_scoreboard) m_analysis_imp;
  ahb_pkt 	m_ahb_pkt_q[$];
  
  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    m_analysis_imp = new("m_analysis_imp", this);
  endfunction
  
  virtual function write(ahb_pkt l_ahb_pkt);
    `uvm_info(get_type_name(), $sformatf("[write] Got packet %s", l_ahb_pkt.convert2string()), UVM_MEDIUM)
    m_ahb_pkt_q.push_back(l_ahb_pkt);
  endfunction
endclass

//---------------------------------------------------------------------------------
// base_env : Base environment to contain agent and other testbench structures
//---------------------------------------------------------------------------------
class base_env extends uvm_env;
  `uvm_component_utils(base_env)
  function new(string name = "base_env", uvm_component parent=null);
    super.new(name, parent);
  endfunction
  
  ahb_agent   		m_ahb_agent;
  base_scoreboard 	m_base_scbd;
  
  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    m_ahb_agent = ahb_agent::type_id::create("m_ahb_agent", this);
    m_base_scbd = base_scoreboard::type_id::create("m_base_scbd", this);
  endfunction
  
  virtual function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    m_ahb_agent.m_mon.m_analysis_port.connect(m_base_scbd.m_analysis_imp);
  endfunction
  
endclass

//---------------------------------------------------------------------------------
// base_test : Test class
//---------------------------------------------------------------------------------    
class base_test extends uvm_test;
  `uvm_component_utils(base_test)
  function new(string name = "base_test", uvm_component parent=null);
    super.new(name, parent);
  endfunction
  
    virtual ahb_if	m_ahb_vif;
  
  	ahb_cfg 	 	m_ahb_cfg;
  	ahb_seq 		m_ahb_seq;
	base_env 		m_env;
  
  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
   
    // Get virtual interface from tb_top
    if (!uvm_config_db #(virtual ahb_if)::get(this, "", "m_ahb_if", m_ahb_vif))
        `uvm_fatal(get_type_name(), $sformatf("[CFG] Did not find m_ahb_if in config_db"))
    
    // Set up ahb agent configuration, assign virtual interface handle and set in config_db
    m_ahb_cfg = ahb_cfg::type_id::create("m_ahb_cfg");
    m_ahb_cfg.m_ahb_vif = m_ahb_vif;        
    uvm_config_db #(ahb_cfg)::set(this, "*ahb_agent*", "m_ahb_cfg", m_ahb_cfg);
        
    // Create base env, test sequence
    m_ahb_seq = ahb_seq::type_id::create("m_ahb_seq");
    m_env = base_env::type_id::create("m_env", this);
  endfunction
  
  virtual task reset_phase(uvm_phase phase);
    super.reset_phase(phase);
    phase.raise_objection(this);
	m_ahb_vif.hresetn = 0;    
    repeat(5) @ (m_ahb_vif.cb);
	m_ahb_vif.hresetn = 1;
    repeat(5) @ (m_ahb_vif.cb);
    phase.drop_objection(this);
  endtask
  
  virtual task main_phase(uvm_phase phase);
    super.main_phase(phase);
    phase.raise_objection(this);
    m_ahb_seq.start(m_env.m_ahb_agent.m_seqr);
    phase.drop_objection(this);
  endtask
endclass

//---------------------------------------------------------------------------------
// AHB interface
//---------------------------------------------------------------------------------    
interface ahb_if (input hclk);
  logic 		hresetn;
  logic [31:0] 	haddr;
  logic [2:0] 	hburst;
  logic 		hmastlock;
  logic [3:0] 	hprot;
  logic [2:0] 	hsize;
  logic [1:0] 	htrans;
  logic [31:0] 	hwdata;
  logic 		hwrite;
  
  logic [31:0]	hrdata;
  logic 		hreadyout;
  logic  		hresp;
  
  logic 		hsel;
  
  clocking cb @ (posedge hclk);
    input hreadyout, hrdata, hresp;
    output haddr, hburst, hmastlock, hprot, hsize, htrans, hwdata, hwrite, hsel;
  endclocking
endinterface

//---------------------------------------------------------------------------------
// Testbench TOP module
//---------------------------------------------------------------------------------        
module tb;
  bit clk;
  
  always #10 clk = ~clk;
  
  ahb_if 	m_ahb_if ( .hclk (clk));
  
  assign m_ahb_if.hresp = 0;
  
  initial begin
    m_ahb_if.hreadyout <= 0;
    forever begin
      repeat ($urandom_range(2,6)) @ (posedge clk);
      m_ahb_if.hreadyout <= ~m_ahb_if.hreadyout;
    end
  end
  
  initial begin
    m_ahb_if.hrdata <= 0;
    forever begin
      repeat ($urandom_range(1,3)) @ (posedge clk);
      m_ahb_if.hrdata <= $random;
    end
  end
    
  initial begin
    uvm_config_db #(virtual ahb_if)::set(null, "uvm_test_top", "m_ahb_if", m_ahb_if);
    run_test("base_test");
  end
  
  initial begin
    $dumpvars;
    $dumpfile("dump.vcd");
  end
endmodule

design.sv
// Code your design here
Admin mode — edit and delete controls are visible on each row. Use the IDE to add new snippets via File → Save as Snippet.