UVMC command API and config db

I am working, with Hans, on integrating a C++ model using UVM Connect into a SystemVerilog simulation. The model requires some static configuration at start of simulation. I decided to pass SV simulation command-line arguments (+plusargs), and send them over to SystemC.

Going over the documentation, command API chapter and the config db seemed what I need. I tried sending over a string list to the other side using UVMC_set_config_int (for length of the list), and multiple UVMC_set_config_string for each element of the list.

First I noticed, documentation mentions uvmc_cmd_init() which does not really exist! I switched that to uvmc_init() and things started working.

Second, I am not sure if I am using things as they should not be used that way or not. Documentation mentions that command API is intended to control the SV side from SC side. My use case is sending config data from SV to SC. The documentation does not mention UVMC_* (uppercase functions). I used the upper case ones on the SV side and lowercase ones (uvmc_*) on SC side.

I observed a few issues and I wonder what I am doing wrong.

I tried UVMC_set_config_int/UVMC_get_config_int on SV side, but the get function fails and returns 0. I also used UVM_CONFIG_DB_TRACE and UVMC_COMMAND_TRACE to debug and for this code:

string args[] = {"--arg1", "--arg2", "--arg3"};

bit              b;
longint unsigned argc = args.size();

UVMC_set_config_int("", "TEST", "argc", argc);
b = UVMC_get_config_int("", "TEST", "argc", argc);

$display($sformatf("argc: %0d --> (%0d)", argc, b));

I see:

UVM_INFO uvmc_commands.sv(638)    @ 0: reporter [TRACE/UVMC_CMD/SET_CFG_INT] contxt='' inst_name='TEST' field_name='argc' value=3
UVM_INFO uvmc_commands.sv(781)    @ 0: reporter [TRACE/UVMC_CMD/GET_CFG_INT] contxt= inst_name=TEST field_name=argc
UVM_INFO uvm_resource_db.svh(121) @ 0: reporter [CFGDB/GET] Configuration 'TEST.argc' (type logic signed[4095:0]) read by  = null (failed lookup)
argc: 0 --> (0)

Then I send the string elements:

$display("args:");
for (int i = 0; i < args.size(); i++) begin
  bit    b;
  string field;
  string str;

  $display("  [%0d]: %s", i, args[i]);
  field = $sformatf("args_%0d", i);
  UVMC_set_config_string("", "TEST", field, args[i]);

  b = UVMC_get_config_string("", "TEST", field, str);
  $display("--> %s - arg[%0d]: '%s' --> %0d", field, i, str, b);
end

And I see:

args:
   [0]: --arg1
UVM_INFO uvmc_commands.sv(680) @ 0: reporter [TRACE/UVMC_CMD/SET_CFG_STR] contxt='' inst_name='TEST' field_name='args_0' value='49672931665713'
UVM_INFO uvmc_commands.sv(819) @ 0: reporter [TRACE/UVMC_CMD/GET_CFG_STR] contxt= inst_name=TEST field_name=args_0
UVM_INFO uvm_resource_db.svh(121) @ 0: reporter [CFGDB/GET] Configuration 'TEST.args_0' (type string) read by  = null (failed lookup)
--> args_0 - arg[0]: '' --> 0
   [1]: --arg2
UVM_INFO uvmc_commands.sv(680) @ 0: reporter [TRACE/UVMC_CMD/SET_CFG_STR] contxt='' inst_name='TEST' field_name='args_1' value='49672931665714'
UVM_INFO uvmc_commands.sv(819) @ 0: reporter [TRACE/UVMC_CMD/GET_CFG_STR] contxt= inst_name=TEST field_name=args_1
UVM_INFO uvm_resource_db.svh(121) @ 0: reporter [CFGDB/GET] Configuration 'TEST.args_1' (type string) read by  = null (failed lookup)
--> args_1 - arg[1]: '' --> 0
   [2]: --arg3
UVM_INFO uvmc_commands.sv(680) @ 0: reporter [TRACE/UVMC_CMD/SET_CFG_STR] contxt='' inst_name='TEST' field_name='args_2' value='49672931665715'
UVM_INFO uvmc_commands.sv(819) @ 0: reporter [TRACE/UVMC_CMD/GET_CFG_STR] contxt= inst_name=TEST field_name=args_2
UVM_INFO uvm_resource_db.svh(121) @ 0: reporter [CFGDB/GET] Configuration 'TEST.args_2' (type string) read by  = null (failed lookup)
--> args_2 - arg[2]: '' --> 0

For some reason, I see another set of reads (get)! The argc is correct, and I see multiple TEST.args_2 reads!

UVM_INFO uvm_resource_db.svh(121) @ 0: reporter [CFGDB/SET] Configuration 'TEST.argc' (type logic signed[4095:0]) set by  = (logic signed[4095:0]) 3
UVM_INFO uvm_resource_db.svh(121) @ 0: reporter [CFGDB/SET] Configuration 'TEST.args_2' (type string) set by  = (string) "--arg3"
UVM_INFO uvm_resource_db.svh(121) @ 0: reporter [CFGDB/SET] Configuration 'TEST.args_2' (type string) set by  = (string) "--arg3"
UVM_INFO uvm_resource_db.svh(121) @ 0: reporter [CFGDB/SET] Configuration 'TEST.args_2' (type string) set by  = (string) "--arg3"

Interestingly, on the SV side, when I readback (get) what was written (set) into the config db using UVMC_*, I see failed lookup!

On the SC side I have:

std::cout << std::string(120, '-') << std::endl;

if ( uvmc_get_config_int("", "TEST", "argc", argc) )
  std::cout << "SC : argc: " << argc << std::endl;
else
  UVMC_ERROR("GET_CFG_INT_FAIL", "get_config_int failed", name());

args = std::vector<std::string>(argc);

for ( size_t i = 0; i < argc; i++ )
{
  std::string field = "args_" + std::to_string(i);
  uvmc_get_config_string("", "TEST", field.c_str(), args[i]);
  std::cout << "SC : args[" << i << "]: " << args[i] << std::endl;
}

I see:

UVM_INFO uvm_resource_db.svh(121) @ 0: reporter [CFGDB/GET] Configuration 'TEST.argc' (type logic signed[4095:0]) read by  = (logic signed[4095:0]) 3
SC : argc: 3
UVM_INFO uvmc_commands.sv(819) @ 0: reporter [TRACE/UVMC_CMD/GET_CFG_STR] contxt= inst_name=TEST field_name=args_0
UVM_INFO uvm_resource_db.svh(121) @ 0: reporter [CFGDB/GET] Configuration 'TEST.args_0' (type string) read by  = null (failed lookup)
SC : args[0]: ''
UVM_INFO uvmc_commands.sv(819) @ 0: reporter [TRACE/UVMC_CMD/GET_CFG_STR] contxt= inst_name=TEST field_name=args_1
UVM_INFO uvm_resource_db.svh(121) @ 0: reporter [CFGDB/GET] Configuration 'TEST.args_1' (type string) read by  = null (failed lookup)
SC : args[1]: ''
UVM_INFO uvmc_commands.sv(819) @ 0: reporter [TRACE/UVMC_CMD/GET_CFG_STR] contxt= inst_name=TEST field_name=args_2
UVM_INFO uvm_resource_db.svh(121) @ 0: reporter [CFGDB/GET] Configuration 'TEST.args_2' (type string) read by  = (string) "--arg3"
SC : args[2]: '--arg3'

Again, argc value is correct, even though the get on SV side fails.
The TEST.args_0 and TEST.args_1 fail and the last TEST.args_2 has correct value.

It is not clear if my use case is not correct and this mode of operation was never designed to work this way or something else.

Or maybe I should use generic payload instead of config db for this case as well.

I can pack up a small testcase if that helps. Any help or guidance is appreciated for this static configuration setup.

Cheers,
– Amal

Just a note that if I use pure uvm::uvm_config_db set/get on SV side instead of UVMC_set/get function calls, all this works properly. So maybe my use case and using the UVMC_* calls on SV is wrong.

I think my assumptions was that I could use the same DPI exported functions on SV side. If these cannot work on SV side, maybe they should be hidden/private from user’s perspective.

Amal,

For issue #1 you are correct. uvmc_cmd_init() was actually an error
in the comments of the source code (and hence the generated documentation).

Should have been uvmc_init() in all places. We have made changes accordingly
which will be reflected in next release.

For issue #2 yes that is correct. UVMC_set/get* functions are meant
only to be DPI helper functions for the SystemC side. They are not meant
to be used directly by SV code.

In fact the entire UVMC Command API itself which includes not only these
functions but an assortment of others for things like raising objections,
sync’ing to UVM phases, etc are all meant to provide a way for SystemC to
“remote control” the SV UVM infrastructure, i.e. to extend some of the UVM
functionality over to the System C domain.

Here’s an excerpt from the UVMC primer that explains it pretty well I think,

49 UVMC Command API

This section describes the API for accessing and controlling UVM simulation in SystemVerilog from
SystemC (or C or C++). To use, the SV side must have called the uvmc_init, which starts a background
process that receives and processes incoming commands.
The UVM Connect library provides an SystemC API for accessing SystemVeilog UVM during simulation.

With this API users can:
• Wait for a UVM to reach a given simulation phase
• Raise and drop objections
• Set and get UVM configuration
• Send UVM report messages
• Set type and instance overrides in the UVM factory
• Print UVM component topology

So yes on the SV side your method for accessing the the config DB is exactly
right, i.e. the native way SV-UVM code does it.

– johnS

1 Like