Thought Leadership

So You Want a Different UVM Report Server. Doesn’t Everyone? Where To Start…

By Rich Edelman

So. You want a different report server. Maybe something fancier. Maybe something simpler. Maybe something with special formatting.

How to get started?

Good news – it’s easy. This is an example of customizing a UVM report server using the new IEEE Std 1800.2-2017. This example will not work on UVM 1.1d or UVM 1.2, but with some changes it should. The idea is the same in each UVM version. Replace the default report server with a custom version.

In the discussion below, the default UVM report server will be replaced with a custom report server which produces messages which have column-ized fields. Object Oriented concepts will be used: inheritance and function override. The custom report server changes are simple. The default report server will be extended and then a key function call, compose_report_message(), will be replaced with a custom version. Only a few lines of code will be changed in compose_report_message().

The first thing to do is to create a package that can be used for the new report server – “”. This package will define a couple of helper functions.

  • tail_width() returns the LAST few characters of its argument string.
  • fixed_width() returns the argument string either truncated to the specified width, or white space padded to that width.

These helper functions will be used in the custom report server.

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

  function string tail_width(string s, int width);
    string tmp;
    int m, n;
    if (s.len() > width) begin
      m = s.len()-width;
      n = s.len()-1;
      tmp = s.substr(m, n);
      tmp = s;
    return fixed_width(tmp, width);

  function string fixed_width(string s, int width);
    string tmp;
    if (s.len() > width) begin
      // s is longer, truncate
      tmp = s.substr(0, width-1);
    else begin
      // s is shorter. whitespace fill
      int n;
      n = width - s.len();
      tmp = {s, {n{" "}}};
    return tmp;

  `include "my_report_server.svh" 

The new report_server itself is in the file “my_report_server.svh“:

  class my_report_server_t extends uvm_default_report_server;
    virtual function string compose_report_message(uvm_report_message report_message,
                                                   string report_object_name = "");

Above, a new class, ‘my_report_server_t’, is created by extending uvm_default_report_server. Copy the entire contents of the function ‘compose_report_message()’ from the uvm_report_server.svh::uvm_default_report_server class. That code is about 60 lines of formatting code. Edit the formatting as desired – just a couple of lines.

The body of the built-in compose_report_message() uses the uvm_report_message structure, and formats each piece. Then at the end of the routine, those formatted pieces are concatenated into a string. That concatenated string is the “composed message”. The new, replacement report server is to have a different “composed string”.

The original string concatenation is below

    compose_report_message = {sev_string, verbosity_str, " ", filename_line_string, "@ ",
      time_str, ": ", report_object_name, context_str,
      " [", report_message.get_id(), "] ", msg_body_str, terminator_str};

The new string concatenation is below. The BOLD text above is changed to the BOLD text below. Same for BOLD Italic.

    compose_report_message = {sev_string, verbosity_str, " ", filename_line_string, "@ ", 
      time_str, ": ", tail_width({report_object_name, context_str}, 10), 
      " [", fixed_width(report_message.get_id(), 12), "] ", msg_body_str, terminator_str};

In the case of the report_object_name and context_str, just the last 10 characters are returned. For example, a name like “uvm_test_top.VIPA.environment_c.agent_1.driver3” will be displayed as “_1.driver3”. For the get_id() (the Message ID), a fixed size string of 12 characters are returned. The string will either be extended with whitespace to 12 characters, or truncated to 12 characters – in both cases resulting in a 12 character field. Filename_line_string is formatted in a different section of compose_report_message(). Get the example to see.

Helper functions have been created: tail_width() and fixed_width(), along with a new report server class, containing an overridden compose_report_message function. Now to put it all to good use.

In the top level, or in the test – somewhere early in simulation, the new report server class needs to be constructed, and then it needs to replace the default report server. For example:

  module top();
    initial begin
      my_report_server_t my_report_server;
      my_report_server = new("my_report_server");

A class handle is declared and constructed, and then a call to ‘set_report_server()’ in uvm_coreservice_t installs the replacement. Done.

The output is “columnized”. The file-path-name, the UVM hierarchical path and the Message ID, have been made to fit in the various column sizes. (See BOLD below).

  # UVM_INFO b/sim/ 114) @ 1285: t_top.a1.d [driver4     ] Got [transaction            ] data=96
  # UVM_INFO b/sim/ 114) @ 1288: t_top.a2.d [driver3     ] Got [transaction            ] data=96
  # UVM_INFO b/sim/ 114) @ 1290: t_top.a2.d [driver3     ] Got [my_special_transaction ] data=97
  # UVM_INFO b/sim/ 114) @ 1290: t_top.a1.d [driver4     ] Got [my_special_transaction ] data=97
  # UVM_INFO b/sim/ 114) @ 1295: t_top.a1.d [driver4     ] Got [transaction            ] data=98
  # UVM_INFO b/sim/ 114) @ 1296: t_top.a2.d [driver3     ] Got [transaction            ] data=98
  # UVM_INFO b/sim/ 114) @ 1301: t_top.a2.d [driver3     ] Got [my_special_transaction ] data=99
  # UVM_INFO b/sim/ 114) @ 1302: t_top.a1.d [driver4     ] Got [my_special_transaction ] data=99
  # UVM_INFO b/sim/ 114) @ 1306: t_top.a1.d [driver4     ] Got [transaction            ] data=100
  # UVM_INFO b/sim/ 114) @ 1307: t_top.a2.d [driver3     ] Got [transaction            ] data=100
  # UVM_INFO b/sim/  89) @ 1311: qr@@seq1-3 [my_sequence ] Finished
  # UVM_INFO b/sim/  89) @ 1312: qr@@seq2-3 [my_sequence ] Finished

It took a couple of helper functions, two lines of change in compose_report_message() and 3 lines of initialization and installation. Easy. Source code is available for this example. Please email if you would like it.

Come see and hear more about the UVM and find out about the new UVM IEEE standard at DVCON this year, February 25-28, 2019.

UVM at DVCON includes

Or stop by the Mentor Booth to chat during the DVCON Expo. I’ll be there and I love to talk UVM and Debug. (Tuesday, 5-7, Wednesday 2:30-6, Thursday 2:30-6).

See you at the show.

Get the UVM. Download UVM 1.1d  or UVM 1.2

Download UVM IEEE Std. 1800.2-2017 It’s free. Create a free account. Download.


Mentor DVCON Expo Theater Schedule (Located in the Mentor Booth)

Monday | February 25

5:00pm Portable Stimulus from IP to SoC – Achieve More Verification with Questa inFact
5:45pm Accelerate SoC Power, Veloce Strato – PowerPro
6:30pm Exploring Veloce DFT and Fault Apps

Tuesday | February 26

3:00pm Mentor Safe IC – ISO 26262 & IEC 61508 Functional Safety
3:45pm Adding Determinism to Power in Early RTL Using Metrics
4:30pm Scaling Acceleration Productivity Beyond Hardward
5:15pm Adding Determinism to Power in Early RTL Using Metrics

Wednesday | February 27

3:00pm Verification Signoff of HLS C++/SystemC Designs
4:00pm An Emulation Strategy for AI and ML Designs
5:00pm Advanced UVM Debugging



3 thoughts about “So You Want a Different UVM Report Server. Doesn’t Everyone? Where To Start…

Leave a Reply

This article first appeared on the Siemens Digital Industries Software blog at