UVMF_JTAG - muneeb-mbytes/UVMF GitHub Wiki

UVM Framework

Advanced verification methodologies like UVM (Universal Verification Methodology) enable higher level efficiency and re-usable structure. However many product teams do not take such productivity and quality benefits because they overestimate the ramp-up time required to introduce UVM. In order to increase the time-to-productivity Mentor Graphics created a framework. The so called UVM Framework provides a set of common UVM based testbench building blocks that are ready to use without the necessity of detailed UVM knowledge.

image

                                              Fig 1: UVM Framework     

Motivation for using UVMF

1. UVM Jumpstart The UVM Framework (UVMF) provides a jump-­‐start for learning UVM and building UVM verification environments. It defines an architecture and reuse methodology upon UVM, enabling teams new to UVM to be productive from the beginning while coming up the UVM learning curve. The python scripts provided automate the creation of the files, infrastructure and interconnect for interface packages, environment packages and project benches. Once generated, developers can promptly focus on adding functionality specific to the design and interfaces used.

2. Reuse Methodology

The UVM Framework is a model reuse methodology that verification teams can leverage. It supports component level verification reuse across projects and environment reuse from block through chip to system level simulation. The UVM Framework is an established verification reuse methodology that is in use at many companies in multiple industries across North America and Europe.

3. Single Architecture for Simulation and Emulation

The UVM Framework provides an architecture that supports pure simulation and accelerated simulation using emulation. This enables the creation of a single unified environment that supports block, chip and system level tests, and with the choice of running on a pure simulation platform (e.g. Questa) or a hardware-­‐assisted acceleration platform using emulation (e.g. Veloce).

4. Coverage Within UVMF

UVMF provides a mechanism for rapid creation of reusable simulation infrastructure. Coverage collection components can be defined and connected in the environment using the UVMF code generators. The list below identifies components where functional coverage can be collected and how to add coverage to these components:

  • Coverage component: Create this component using the define Analysis Component API and connect to other components in the environment generator. It will likely have all analysis exports and no analysis ports.

  • Predictor: Manually add required cover groups to the predictor that was generated using define Analysis Component.

  • Scoreboard: Extend UVMF scoreboards on a per-­‐environment basis to define cover groups and sample coverage based on DUT output transactions.

Major Divisions of Functionality Within UVMF

  • UVMF Base Package

The UVMF base package, uvmf_base_pkg, is a library of base classes that implement core functionality of components found in all simulation benches. This includes base classes for transactions, sequences, drivers, monitors, predictors, scoreboards, environments and tests. All classes in the UVMF base package are derived from UVM classes.

  • Interface Packages

UVMF interface packages and their associated BFMs provide all of the functionality required to monitor and optionally drive a design interface. Interface packages and BFMs are reusable across projects. An interface package is composed of three pieces: a signal bundle interface, BFM interfaces and the package declaration. The signal bundle contains all signals used in the protocol. The BFMs implement the protocol signaling to drive and monitor transactions at the pin level. The package declaration includes all class definitions and type definitions used by the interface agent.

  • Environment Packages

The environment package is a key aspect that enables vertical reuse of environments within the UVMF. The environment package contains the environment class definition, its configuration class definition and any environment level sequences that could be used in higher level simulations. Block level environments contain agents, predictors, scoreboards, coverage collectors and other components.

  • Verification IP

The verification_ip folder contains all packages that are reused across projects and from block to top. This folder contains environment packages, interface packages, utility packages, etc.

  • Project Benches

The simulation bench is composed of top level elements that are not generally intended to be reusable horizontally nor vertically. It defines test level parameters, the top level modules, top level sequence and top level UVM test.

YAML

Rules for Creating YAML file

When you are creating a file in YAML, you should remember the following basic rules −

  • YAML is case sensitive

  • The files should have .yaml as the extension

  • YAML does not allow the use of tabs while creating YAML files; spaces are allowed instead

Basic Components of YAML File

The basic components of YAML are described below −

  • Conventional Block Format

This block format uses hyphen+space to begin a new item in a specified list. Observe the example shown below −

  • Inline Format

Inline format is delimited with comma and space and the items are enclosed in JSON.

  • Maps

A map is a collection of key->value pairings. You may be familiar with these if you’ve ever worked with Python dictionaries or HashMaps in other languages. Each key must be unique, values can be anything, and ordering does not matter.

image

                                              Fig 2: Maps  

This is a simple map that represents a person’s name and age. There are two keys (name and age), and each maps to a particular value.

  • Lists

A list is a sequence of ordered values. Arrays in many programming languages are implementations of lists.

image

                                               Fig 3: Lists  
  • Indentation

Indentation is used in YAML to create nesting, or parent/child relationships. This is similar to how scoping works in Python. For example we can define a complex “user” data structure using indentation to neatly organize each field:

image

                                                Fig 4: Indentation     

JTAG INTERFACE

JTAG (named after the Joint Test Action Group which codified it) is an industry standard for verifying designs and testing printed circuit boards after manufacture.

It specifies the use of a dedicated debug port implementing a serial communications interface for low-overhead access without requiring direct external access to the system address and data buses.
The interface connects to an on-chip Test Access Port (TAP) that implements a stateful protocol to access a set of test registers that present chip logic levels and device capabilities of various parts.

image

The connector pins are:

  1. TDI (Test Data In):This signal represents the data shifted into the device’s test or programming logic. It is sampled at the rising edge of TCK when the internal state machine is in the correct state.As with any clocked signal, data presented to TDI must be valid for some chip-specific Setup time before and Hold time after the relevant (here, rising) clock edge.

  2. TDO (Test Data Out):This signal represents the data shifted out of the device’s test or programming logic and is valid on the falling edge of TCK when the internal state machine is in the correct state. TDO data is valid for some chip-specific time after the falling edge of TCK.

  3. TCK (Test Clock): This signal synchronizes the internal state machine operations.

  4. TMS(Test Mode Select): This signal is sampled at the rising edge of TCK to determine the next state.

  5. TRST (Test Reset) (optional): The TRST pin is an optional active-low reset to the test logic, usually asynchronous, but sometimes synchronous, depending on the chip. If the pin is not available, the test logic can be reset by switching to the reset state synchronously, using TCK and TMS. Note that resetting test logic doesn't necessarily imply resetting anything else. There are generally some processor-specific JTAG operations which can reset all or part of the chip being debugged.

YAML interface structure All interface ports, transaction data, and configuration are declared and initialized with in the interface names in the interface YAML data structure.

Jtag Block Diagram :

jtag_diagram

                            Fig 5 : JTAG block diagram

YAML interface structure

All interface ports, transaction data, and configuration are declared and initialized with in the interface names in the interface YAML data structure. This information is used to create the following content: Classes: Transaction, interface level sequence base, random sequence, coverage, driver, monitor, agent, agent configuration, UVM reg predictor.
• Package: Protocol package including all classes listed above.
• BFMs: Driver and monitor.

JTAG interface Connection with TB

JTAG

                                             Fig 6: JTAG interface Connection with TB 

The fig shows the port declaration with respect to the testbench.

YAML JTAG interface structure code snippet

  uvmf:
    interfaces:
     "jtag":
      clock: "clock"
      reset: "reset"
      reset_assertion_level: "True"
      veloce_ready: "True"
      ports: 
        - name: "tck"   
          width: "1"        
          dir: "output"
          reset_value: "1'b0"
        - name: "tms"  
          width: "1"         
          dir: "output"
          reset_value: "1'b0"
        - name: "tdi"  
          width: "1"       
          dir: "output"
          reset_value: "1'b0" 
        - name: "tdo" 
          width: "1" 
          dir: "input"
          reset_value: "1'b0"
      transaction_vars:
        - name: "tck"  
          type: "bit"
          isrand: "False"
          iscompare: "True" 
        - name: "tms" 
          type: "bit"
          isrand: "True"
          iscompare: "True" 
        - name: "tdi"    
          type: "bit"
          isrand: "True" 
          iscompare: "True" 
        - name: "tdo"
          type: "bit"           
          isrand: "False" 
          iscompare: "True"

      config_vars:
        - name: "is_active"
          type: "bit"
          isrand: "False"
          value: "1"
        - name: "no_of_slaves"
          type: "int"
          value: "1"
          isrand: "True"
        - name: "has_coverage"
          type: "bit"
          value: "1"

      config_constraints:
        - name: "slavecount"
          value: "{ no_of_slaves>0;no_of_slaves<17 }"    
     

The above code shows the code structure of the YAML JTAG interface structure it is found in the directory UVMF_JTAG with the file name jtag_interface.yaml

Interfaces:
Under Interface we declare the "jtag" interafce, it is used to hold the data information or signals related to JTAG.

clock
Identifies the primary clock to be used in the interface agent as ‘clk’.

reset
Name of primary reset.

reset_assertion_level
Identifies the primary reset to be used in the interface agent as ‘rst’ with active low polarity. if reset_assertion_level is true then it is active high polarity else active low.

veloce_ready
Run a Testbench simulation with HDL components running on the Veloce emulator.If the veloce_ready section is set to True in the interface YAML file, the generated interface is ready for use in simulation and emulation.

ports:
Defines a port definition for use in an interface wire bundle. port declaration we declare the input and output signal of JTAG in perspective of Jtag_testbench.

code_structure:

 ports:
  - name: "name"  
    width: "width"  
    dir: "dir"  
  • name: describes the names of the protocol related signals for example JTAG signals are TCK,TMS,TDO and TDI
  • width: Related to the range of the signal.
  • dir: Describe the direction of the signal.

The port declaration related to JTAG protocol is shown in below snippet

  ports:
   - name: "tck"
     dir: "output"
     width: "1"
   - name: "tms"
     dir: "output"
     width: "1"
   - name: "tdi"
     dir: "output"
     width: "1"
   - name: "tdo"
     dir: "input"
     width: "1"

transaction_variables:
Defines a transaction to be placed within an interface’s sequence item definition. This Transaction_vars is a packet used to send the data between the classes

code_structure:

     transaction_vars:
      - name: "<name>"
        type: "<type>"

-name: related to the name of the signal -type: Related to the type of data example: int_type, bit_type, byte_type

The transaction variables related to JTAG protocol is shown in below snippet

  transaction_vars:
   - name: "tck"
     type: "bit"
   - name: "tms"
     type: "bit"
   - name: "tdi"
     type: "bit"
   - name: "tdo"
     type: "bit"

configuration variables
Defines a configuration variable to use in the given interface. we can declare the conditions, declare the no of slaves.

code_structure:

     config_vars:
      - name: "<name>"
        type: "<type>"
        value: "value" 

-name: signals related to setting the configuration to the defined protocol.
-type: Related to the type of data example: int_type, bit_type, byte_type.
-value: is provided, this will initialize the variable with the specified value at the beginning of simulation.

The configuration variables related to JTAG protocol is shown in below snippet

 #configuration variables
  config_vars:
   - name: "is_active"
     type: "bit"
     value: '1'
   - name: "no_of_slaves"
     type: "int"
     value: '1'
   - name: "has_coverage"
     type: "bit"
     value: '1'

Built-in Analysis Port

Each UVMF agent contains an analysis_export named monitored_ap. Information observed during the protocol transfer by the monitor BFM are sent to the monitor class. The monitor class places the information within a UVM sequence item. The sequence item is then broadcasted from the agent’s analysis_port named monitored_ap.


Step to generate UVMF code

  • Command to generate the JTAG Interface code

    python $UVMF_HOME/UVMF_JTAG/yaml2uvmf.py jtag_interface.yaml

    $UVMF_HOME is a path from the root directory to the present UVMF_2022.3.

    So, python yaml2uvmf.py jtag_interface.yaml

Note: By default the generated code will be placed in uvmf_template_output directory, but we can change the destination directory name using:
python yaml2uvmf.py <yaml_files> --dest_dir=<dir_name>

--dest_dir=<dir_name> - Override default destination directory of uvmf_template_output

python yaml2uvmf.py jtag_interface.yaml --dest_dir=yaml_jtag_output


Output:

jtag_output

Above figure shows the files generated in src/ folder by running the jtag_interface.yaml file and description of all those generated files given below.

  • The following files listed are the interface generated named as jtag_pkg.
  • Files generated are under the ./yaml_jtag_output/verification_ip/interface_packages/jtag_pkg/src directory.

jtag2reg_adapter.svh

  • If the interface will be used with a UVM register model, fill in the bus2reg() and reg2bus() functions.
  • User has to fill their own functionality into this file.

jtag_if.sv

  • This file contains the signal interface for the agent. User can optionally add protocol assertions in here.

code snippet

import uvmf_base_pkg_hdl::*;
import jtag_pkg_hdl::*;

interface  jtag_if 

  (
  input tri clk, 
  input tri rst,
  inout tri  tck,
  inout tri  tms,
  inout tri  tdi,
  inout tri  tdo
  );

modport monitor_port 
  (
  input clk,
  input rst,
  input tck,
  input tms,
  input tdi,
  input tdo
  );

modport initiator_port 
  (
  input clk,
  input rst,
  output tck,
  output tms,
  output tdi,
  input tdo
  );

modport responder_port 
  (
  input clk,
  input rst,  
  input tck,
  input tms,
  input tdi,
  output tdo
  );
  

// pragma uvmf custom interface_item_additional begin
// pragma uvmf custom interface_item_additional end

endinterface

jtag_agent.svh

  • agent class code in uvm is defined in this file.

code snippet

class jtag_agent  extends uvmf_parameterized_agent #(
                    .CONFIG_T(jtag_configuration ),
                    .DRIVER_T(jtag_driver ),
                    .MONITOR_T(jtag_monitor ),
                    .COVERAGE_T(jtag_transaction_coverage ),
                    .TRANS_T(jtag_transaction )
                    );

  `uvm_component_utils( jtag_agent )

// pragma uvmf custom class_item_additional begin
// pragma uvmf custom class_item_additional end

// ****************************************************************************
// FUNCTION : new()
// This function is the standard SystemVerilog constructor.
//
  function new( string name = "", uvm_component parent = null );
    super.new( name, parent );
  endfunction

// ****************************************************************************
  // FUNCTION: build_phase
  virtual function void build_phase(uvm_phase phase);
// pragma uvmf custom build_phase_pre_super begin
// pragma uvmf custom build_phase_pre_super end
    super.build_phase(phase);
    if (configuration.active_passive == ACTIVE) begin
      // Place sequencer handle into configuration object
      // so that it may be retrieved from configuration 
      // rather than using uvm_config_db
      configuration.sequencer = this.sequencer;
    end
  endfunction
  
endclass

jtag_configuration.svh

  • this file has the agent configuration class and agent configuration will be done here.

code snippet

class jtag_configuration  extends uvmf_parameterized_agent_configuration_base #(
      .DRIVER_BFM_BIND_T(virtual jtag_driver_bfm ),
      .MONITOR_BFM_BIND_T( virtual jtag_monitor_bfm ));

  `uvm_object_utils( jtag_configuration )

  bit is_active = 1;
  int no_of_slaves = 1;
  bit has_coverage = 1;

jtag_driver.svh

  • Driver class to be instantiated in the agent.

jtag_driver_bfm.sv

  • Bus functional model to convert transactions to protocol pin wiggles. Requires user to fill in functionality.

jtag_macros.sv

  • Defines structs type packets and configuration variables which are used to pass data between classes, HDL, HVL and BFMs.

jtag_monitor.svh

  • Monitor class to be instantiated in the agent.

jtag_monitor_bfm.sv

  • Bus functional model to convert the protocol pin wiggles to transactions. Requires user to fill in functionality.

jtag_random_sequence.svh

  • This file contains start sequence. Randomizes the transaction class fields and transfers it to sequencer. this is extended from jtag_sequence_base.

jtag_responder_sequencer.svh

  • If the interface has responder functionality, complete the body of this sequence.

jtag_sequence_base.svh

  • All new sequences should be extended from abc_sequence_base.
  • This Base class has all inherited sequences and has permission to utilize it.

jtag_transaction.svh

  • Sequence_item class used in sequences.
  • Also contains several methods for printing, comparing, etc.

jtag_transaction_coverage.svh

  • If functional coverage from the agent is desired, add bins, crosses, etc., to the generated covergroup.

jtag_typedefs.svh

  • This file contains defines and typedefs used only in the testbench (HVL) side of the testbench. Package may not contain any defines or typedefs after but will still be generated.

jtag_typedefs_hdl.svh

  • This file contains defines and typedefs used by the interface package performing transaction-level simulation activities. This package is used by the driver/monitor BFMs.

Jtag environment yaml

jtag_challenge2_dia

UVMF Environment Packages

  • UVMF uses a separate environment level YAML configuration file to generate the environment level classes.
  • The classes for the environment, its configuration, and sequence are included in the generated environment package.
  • It can optionally include predictor and scoreboard classes.
  • The environment package can be reused when a block level UVMF testbench is being used as part of a subsystem/chip level testbench.
  • The environment config file (JTAG_environment.yaml) is covered the more details.

Code Snippet:

uvmf:
  environments:
    jtag:
      agents:
      - initiator_responder: INITIATOR
        name: jtag_agent_a
        type: jtag_a
      - initiator_responder: INITIATOR
        name: jtag_agent_b
        type: jtag_b
      analysis_components:
      - name: jtag_pred
        parameters: []
        type: jtag_predictor
      analysis_exports: []
      analysis_ports: []
      config_constraints: []
      config_vars: []
      existing_library_component: 'True'
      hvl_pkg_parameters: []
      non_uvmf_components: []
      parameters: []
      qvip_memory_agents: []
      scoreboards:
      - name: jtag_sb
        sb_type: uvmf_in_order_scoreboard
        trans_type: jtag_transaction
      subenvs: []
      tlm_connections:
      - driver: jtag_agent_b.monitored_ap
        receiver: jtag_pred.jtag_agent_b_ae
        validate: 'True'
      - driver: jtag_pred.jtag_sb_ap
        receiver: jtag_sb.expected_analysis_export
        validate: 'True'
      - driver: jtag_agent_a.monitored_ap
        receiver: jtag_sb.actual_analysis_export
       validate: 'True'  

Tells UVMF code generator to include 1 x Jtag_agent_a and 1 x Jtag_agent_b.

  • name defines the instance name
  • type is the name of the agent given by the user in the interface YAML configuration file

Analysis_components:

  • Analysis_ports defines UVMF code generator to include a component of type jtag_predictor with instance name jtag_pred.
  • This jtag_predictor component has not been defined yet and will be described in a separate YAML configuration file.
  • These allow the user to specify analysis exports & ports to add to the environment class, typically implemented when the block level environment is to be utilized within a larger system level UVM testbench.
  • We don’t need to specify anything here for the jtag testbench.

Scoreboard

The scoreboards entry allow the user to specify any scoreboard components to be added the environment class. Here we specify the following for jtag testbench • Add a scoreboard component with instance name = jtag_sb
• The class type for the scoreboard = uvmf_in_order_scoreboard. This is a UVMF base library component
• We define the transaction class that the scoreboard will operate on to be jtag_transaction

TLM_connections

The tlm_connections entry allows the user to specify a point to point connection between 2 ports/exports

  • The driver entry is the start point.
  • The receiver entry is the end point.
  • Validate is checking, it is optional.

Connection 1

image

  • jtag_agent_b : instance name of agent
  • monitored_ap : fixed name for analysis port on all UVMF agents
  • jtag_pred : instance name of jtag predictor
  • jtag_agent_b_ae : fixed name for predictor analysis export

Connection 2

image

  • jtag_pred : instance name of predictor
  • jtag_sb_ap : fixed name for analysis port on scoreboard [‘_ap’ added to inst name]
  • jtag_sb : instance name of scoreboard
  • expected_analysis_export : fixed name for scoreboard ‘expected’ analysis export

Connection 3

image

  • jtag_agent_a : instance name of agent
  • monitored_ap : fixed name for analysis port on all UVMF agents
  • jtag_sb : instance name of jtag scoreboard
  • actual_analysis_export : fixed name for scoreboard ‘actual’ analysis export

Jtag Testbench yaml

The test bench YAML data structure contains information about a bench’s name, top-level environment and a host of optional data regarding how to drive clocks and resets as well as active vs. passive mode settings for underlying BFMs. This information is used to create the following content:
• Classes: Top level test, top level virtual sequence.
• Package: Top level test package, top level sequence package, top level parameters package.
• Modules: hdl_top, hvl_top
• Compilation flow: File list and Makefile

code snippet for JTAG YAML

  uvmf:  
    benches:  
     jtag:  

  active_passive:
  - bfm_name: jtag_agent_a
    value: ACTIVE
  - bfm_name: jtag_agent_b
    value: ACTIVE
    top_env: jtag

syntax:

          bfm_name: "<name>"
          value: "ACTIVE|PASSIVE"

Specifies if the given BFM (specified by "bfm_name") is ACTIVE or PASSIVE for this test bench. If left unspecified the BFM will be ACTIVE.

Example:

          active_passive:
           - bfm_name: jtag_agent_a
             value: ACTIVE
           - bfm_name: jtag_agent_b
             value: ACTIVE
           top_env: jtag

The top level testbench will instantiate the JTAG env (which in turn instantiates the ALU interface agents as well as the environment configuration class

  1. It facilitates the top-down configuration of the environment, which in turn configures the agents.
  2. It provides a default sequences and a default test to run
  3. It provides a simulation directory and makefile/run.do file for compiling and simulating the generated code
  4. The code generated from the bench level config file is specific to the DUT it is testing and in general will be non-reusable code.
⚠️ **GitHub.com Fallback** ⚠️