Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • Start Here4
  • UVM Foundations14
  • UVM Phases & Simulation Lifecycle26
  • Factory & Configuration15
    • UVM Factory: Registration, Overrides and Debug
      • The Factory: Swapping Classes Without Editing the Env
      • Registration Macros: What uvm_component_utils Writes for You
      • The type_id::create Pattern
      • Override Resolution: Who Wins
      • Override Timing, Safety and Debug
      • Factory Advanced: Parameterized, Abstract and By-Name
      • Command-Line Overrides
      • Overriding Items and Sequences
    • config_db and Resources
  • Transaction-Level Modeling (TLM)13
  • UVM Sequences & Stimulus21
  • UVM Agents & Protocol VIP21
  • Environment & Test Classes11
  • Checking & Coverage in UVM21
  • UVM Register Abstraction Layer (RAL)22
  • Advanced UVM in Practice13
  • Debug & Regression10
  • Coding Practice47
  • Verification in Industry Practice10
  • Senior Prep: Architecture, Leadership and Interviews32
Loading lesson

‹UVM Factory: Registration, Overrides and Debug
  1. Topics
  2. UVM Verification
  3. Factory & Configuration
  4. UVM Factory: Registration, Overrides and Debug
  5. The type_id::create Pattern
On this page

    Part 3/Factory & ConfigurationIntermediate

    The type_id::create Pattern

    How to create components and objects through the factory, why new() is legal but bypasses it, and the factory's own create methods.

    A code review comment reads: "Use type_id::create here, new() on a component is illegal." The author pushes back: it compiled and ran. Who is right? Half of each. new() on a component is legal, and it is also the reason a future override will silently do nothing. A senior engineer should be able to say exactly what create does that new does not.

    The idea: create is the only door the factory watches

    Picture a building where the factory is the receptionist. type_id::create walks in through the front door: the receptionist checks the override notes and may send you a different worker. new comes in through the loading dock: perfectly allowed, but nobody checks any notes. The worker you get is always exactly the one you named.

    So the rule is not about legality. A component's constructor is public (only uvm_root hides its constructor), and new("drv", this) builds a working driver. The rule is about substitutability: anything a test might ever want to replace must enter through create.

    The picture

    Sequence diagram: the agent calls type_id create, the proxy calls the factory, the factory resolves the override and constructs the truncating driver, and the handle is cast back.
    Inside one create call in dma_truncate_test. The proxy forwards to the factory with the parent's path; the factory resolves the override, constructs the winner and the proxy casts the result back to the requested type.

    Build it: the create calls you need

    Components: name and parent

    Components are always created with a name and a parent, normally in the parent's build_phase. The parent argument places the component in the hierarchy, and the parent's full name plus the child's name form the instance path that instance overrides and config_db match against.

    design.sv
    // snippet: inside axis_agent::build_phase
    drv = axis_driver::type_id::create("drv", this);   // factory: overrides apply
    // drv = new("drv", this);                        // legal, but no override can ever apply

    Objects: name, and optionally a context

    Objects have no parent in the component tree, so their create takes a name and two optional arguments: a parent component (rarely used) and a context string. The context gives the object an instance path, which is the only way an instance override can target it. The bench's tests create their job configs and sequences with a name only:

    design.sv
    // snippet: object creation as the bench does it, and with a context
    dma_job_cfg job = dma_job_cfg::type_id::create("job");                  // path "job"
    axis_item it = axis_item::type_id::create("it", null, get_full_name()); // path "<seq path>.it"

    With no context, the object's path is just its name, so only type overrides reach it in practice. Path-scoped overrides for items and sequences are covered in Overriding items and sequences.

    The factory's own methods

    type_id::create is a thin wrapper. Underneath are the factory's create methods, which you use when the type is only known at run time, for example from a string or a uvm_object_wrapper held in a config object. The component version takes four arguments and returns a uvm_component, so you cast the result:

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // snippet: creating by type through the factory directly
    uvm_factory    f = uvm_factory::get();
    uvm_component  c;
    c = f.create_component_by_type(axis_driver::get_type(),   // requested type
                                   get_full_name(),            // parent instance path
                                   "drv",                      // name
                                   this);                      // parent
    if (!$cast(drv, c))
      `uvm_fatal("CAST", "factory did not return an axis_driver")

    Method

    Returns

    When to use it

    T::type_id::create(name, parent)

    T

    Every normal component creation.

    T::type_id::create(name, null, contxt)

    T

    Objects; pass a context when an instance override must reach them.

    create_component_by_type(type, parent_path, name, parent)

    uvm_component

    Type held in a variable (uvm_object_wrapper).

    create_object_by_type(type, parent_path, name)

    uvm_object

    The same for objects.

    create_component_by_name(type_name, parent_path, name, parent)

    uvm_component

    Type held as a string, as run_test does with +UVM_TESTNAME.

    run_test itself uses the by-name form. It takes the test name from +UVM_TESTNAME (or its own argument) and calls create_component_by_name(test_name, "", "uvm_test_top", null), which is why the test instance is always called uvm_test_top, and why absolute config paths in the top module can start with that name.

    Where each kind of create belongs

    Components are created during build, normally in the parent's build_phase. Creating a component after the build phase has ended is a fatal error (ILLCRT: it is illegal to create a component after the build phase has ended), because the phases that connect and configure it have already passed. Objects have no such limit: sequences, items and config objects are created whenever they are needed, including thousands of times during run_phase.

    Two related rules. clone() works on objects but not on components, which cannot be copied into a second place in the tree. And the object returned by any create is brand new; nothing is shared with earlier creates unless you share it yourself, which is why the bench's monitors create a fresh item for every transfer.

    In IEEE 1800.2: uvm_factory::get() and uvm_coreservice_t::get().get_factory() return the same factory. Avoid the global factory variable from UVM 1.1-era code; it is not part of 1800.2.

    Watch it run

    In dma_truncate_test, the agent's ordinary create call returned the derived driver, and the log line came from the derived class at the agent's path:

    Diagram
    UVM_INFO dma_tb.sv(520) @ 275000: uvm_test_top.env.in_agt.drv [TRUNC] TLAST forced on beat 3

    The instance name drv and the path uvm_test_top.env.in_agt.drv are exactly what the agent asked for. Only the class changed. That is the contract: the factory may change what is built, never where or under which name.

    What breaks: the helper that called new

    A DV team built a small library of utility sequences. One helper, written quickly, created its items with item = new("item");. Months later a test overrode axis_item with an error-injecting subclass to corrupt one beat in a thousand. The override was registered, other sequences picked it up, and coverage showed error beats arriving. But the failing DMA bug only reproduced with the helper's traffic, and that traffic never contained an error beat. It took a week to see that the helper's items were built through the loading dock.

    The fix was a grep and a rule: no new for anything registered with the factory, except inside the class's own clone/create plumbing. Many teams add a lint check for = new( on registered types. It is cheap and it catches the bug before anyone loses a week.

    "Is calling new() on a component illegal in UVM?"

    A weak answer: "Yes, the constructor is protected, so you must use type_id::create."

    A strong answer: "No. uvm_component's constructor is public; only uvm_root's is protected. new works, but it bypasses the factory, so no type or instance override can ever replace that object. type_id::create forwards to create_component_by_type with the parent's path, the factory resolves overrides for the full instance path, constructs the winner and the proxy casts it back. For objects I pass a context string when I want instance overrides to reach them."

    Follow-ups: What does create_component_by_type return? (a uvm_component, so you $cast it) and How would you create a component whose type is chosen at run time? (hold a uvm_object_wrapper in config and call create_component_by_type).

    Check yourself A sequence creates its items with axis_item::type_id::create("it") and no context. A test registers an instance override for axis_item at uvm_test_top.env.in_agt.sqr.*. Does it apply?

    No. Without a context the item's instance path is just it, which does not match uvm_test_top.env.in_agt.sqr.*. Only a type override (or an instance override whose pattern matches it) reaches it. Pass get_full_name() as the context so the item's path becomes <sequencer path>.<sequence name>.it.

    Check yourself Your env reads a uvm_object_wrapper from config_db that says which scoreboard class to build. Which create call do you use, and what must you do with its result?

    uvm_factory::get().create_component_by_type(wrapper, get_full_name(), "sb", this). It returns a uvm_component, so $cast it into the dma_scoreboard handle and fail loudly if the cast fails. Overrides still apply, because the call goes through the factory.

    Check yourself Two reviewers argue whether new() is fine for a component that "nobody will ever override". What is the practical argument?

    "Nobody will ever override" is a guess about future tests written by other people. The cost of create is one longer line; the cost of new is an override that silently does nothing, found much later. The rule is cheap insurance.

    Next: create asks the factory which class to build. Override resolution answers that question when several overrides could apply.

    Related topics

    • Registration macros

    • Override resolution: who wins

    • Overriding items and sequences

    Previous

    47 / 280

    Next: Override Resolution: Who Wins

    Up next

    Up nextOverride Resolution: Who Wins

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • The Factory: Swapping Classes Without Editing the Env
    • Override Timing, Safety and Debug
    • Factory Advanced: Parameterized, Abstract and By-Name