UVM Connect from SC -> SV without using TLM Generic Payload

Hi,

I am trying to connect SC producer to UVM consumer using UVM Connect and I am getting below error. Any inputs on the same?

UVMC-Error: SC-side proxy channel for ‘producer.out’ with mask ‘4’ and id ‘1’ not compatible with connected SV-side proxy port for ‘cons.in’ with mask ‘7’ and id 1
UVM_ERROR /data/digital/shivaan/wa/UVMC/uvmc-2.3.0//src/connect/sv/uvmc_common.sv(467) @ 0: reporter [UVMC] Cannot bind SV-side UVMC proxy with name ‘cons.in’ or its alternative lookup name, ‘42’ (mask=7)
UVM_FATAL @ 0: reporter [BUILDERR] stopping due to build errors

Port declaration details are as below:

sc_port<tlm_blocking_transport_if > out; - from producer.h
uvmc_connect(prod.out,“42”); - from sc_converter_trans.cpp
uvm_tlm_b_target_socket #(consumer #(T), T) in; - from consumer.sv
uvmc_tlm #(packet)::connect(cons.in, “42”); - from sc_converter_trans.sv

UVMC version is 2.3.0
UVM Version is : 1.1d

Also, is there any working example of UVM Connect for SC → SV “without using TLM Generic Payload”?


Best Regards.

In reply to Shivakumar AN:

Shivakumar,

This raises an issue that may have been fixed in a later release.

I guess you’re asking if the existing examples/converters/sc_converter_trans.sv,.sc
works only for the SV → SC direction and whether we have
one for the SC → SV direction.

The answer is “no” for the UVMC suite. Certainly the more common and better
tested usage is with TLM GP transactions rather than arbitrarily typed ones

  • mainly for performance reasons.

However, that said it would behoove us to create an SC initiator
and an SV target in the same example. I can try this on a later release
and see if I still get the error.

I’ll let you know.
– johnS

In reply to jstickle:

Hi John,

Thanks for the quick reply. Sure, I will wait for the next release.
Yeah, my requirement was SC producer and SV consumer without TLM generic payload as I had to send project specific byte stream data, packet size information and also different kinds of packet based on configuration.

Also, please find the SC → SV non TLM generic example which I tried to run from below link:
Source: Connection between SC -> SV without Generic Payload(GP) | Verification Academy
I got above mentioned errors when I tried to simulate below example.
Awaiting your response.

///// SystemC /////

///// producer.h /////
include
include
using std::string;

include <systemc.h>
include <tlm.h>
using namespace sc_core;
using namespace tlm;

template
class producer : public sc_module {
public:
sc_port<tlm_blocking_transport_if > out;
sc_event done;

producer(sc_module_name nm) : out(“out”)
{
SC_THREAD(run);
}

SC_HAS_PROCESS(producer);

void run() {
sc_time delay;
T t;

    int d_size;
    short cmd;
    int unsigned addr;
    vector<char> data;
    char unsigned tmp;

    d_size = (rand() % 8) + 1;
    for(int i=0; i < d_size; i++) {
      tmp = rand();
      data.push_back(tmp);
    }
    t.set_data_copy(data);

    for (int i=0; i < d_size; i++) {
      printf("===== Loop Number %d / %d =====\n", i+1, d_size);
      delay = sc_time(10,SC_NS);
      cmd  = rand();
      addr = rand();
      t.cmd  = cmd;
      t.addr = addr;
      out->b_transport(t, delay);
    }
    done.notify();

}

};

///// sc_converter_trans.cpp /////
include
using std::vector;

include <systemc.h>
using namespace sc_core;

include “uvmc.h”
using namespace uvmc;

// (begin inline source)
namespace user_lib {

using namespace uvmc;

class packet_base
{
public:

short cmd;
int addr;
vector data;

virtual void do_pack(uvmc_packer &packer) const {
  packer << cmd << addr << data;
}

virtual void do_unpack(uvmc_packer &packer) {
  packer >> cmd >> addr >> data;
}

virtual void set_data_copy(vector<char> data_in) {
  for(int i=0; i < data_in.size(); i++) {
       data.push_back(data_in[i]);
  }
}

};

class packet : public packet_base
{
public:
unsigned int extra_int;

virtual void do_pack(uvmc_packer &packer) const {
  packet_base::do_pack(packer);
  packer << extra_int;
}

virtual void do_unpack(uvmc_packer &packer) {
  packet_base::do_unpack(packer);
  packer >> extra_int;
}

};
}

using namespace user_lib;

UVMC_PRINT_3(packet_base,cmd,addr,data)
UVMC_PRINT_EXT_1(packet,packet_base,extra_int)

include “producer.h”

template
class producer_uvm : public producer {

public:

producer_uvm(sc_module_name nm) : producer(nm) {
SC_THREAD(objector);
}

SC_HAS_PROCESS(producer_uvm);

void objector() {
uvmc_raise_objection(“run”);
wait(this->done);
uvmc_drop_objection(“run”);
}

};

int sc_main(int argc, char* argv)
{
producer_uvm prod(“producer”);
uvmc_connect(prod.out,“stimulus”);
sc_start();
return 0;
}
///// SystemVerilog(UVM) /////

**///// consumer.sv /////
**import uvm_pkg::*;
`include “uvm_macros.svh”

class consumer #(type T=int) extends uvm_component;

uvm_tlm_b_target_socket #(consumer #(T), T) in;

int num_pkts;

`uvm_component_param_utils(consumer #(T))

function new(string name, uvm_component parent=null);
super.new(name,parent);
in = new(“in”, this);
num_pkts = 10;
endfunction : new

virtual task b_transport (T t, uvm_tlm_time delay);
`uvm_info(“CONSUMER/PKT/RECV”,{“\n”,t.sprint()},UVM_MEDIUM)
#(delay.get_realtime(1ns,1e-9));
endtask

endclass

///// sv_converter_trans.sv /////
package user_pkg;

`include “uvm_macros.svh”
import uvm_pkg::*;

class packet_base extends uvm_sequence_item;

`uvm_object_utils(packet_base)

rand shortint cmd;
rand int addr;
rand byte data[$];

function new(string name="");
  super.new(name);
endfunction

constraint c_data_size { data.size() inside { [1:10] }; }

virtual function void do_pack(uvm_packer packer);
  super.do_pack(packer);
  `uvm_pack_int(cmd)
  `uvm_pack_int(addr)
  `uvm_pack_queue(data)
endfunction

virtual function void do_unpack(uvm_packer packer);
  super.do_unpack(packer);
  `uvm_unpack_int(cmd)
  `uvm_unpack_int(addr)
  `uvm_unpack_queue(data)
endfunction

virtual function string convert2string();
  //return $sformatf("addr:%h data:%p",addr,data);
  return $sformatf("addr:%h data:%h",addr,data);
endfunction

virtual function bit do_compare(uvm_object rhs, uvm_comparer comparer);
  packet_base rhs_;
  if (!$cast(rhs_,rhs)) begin
    `uvm_fatal("PKT/COMPARE/BADTYPE",$sformatf("Argument rhs (name=%s type=%s), is not of type packet",rhs.get_name(),rhs.get_type_name()))
    return 0;
  end
  if (!super.do_compare(rhs,comparer))
    return 0;
  if (cmd  != rhs_.cmd)  comparer.result++;
  if (addr != rhs_.addr) comparer.result++;
  if (data != rhs_.data) comparer.result++;
  return (comparer.result == 0);
endfunction

function void do_print(uvm_printer printer);
  super.do_print(printer);
  printer.print_field("cmd",cmd,16);
  printer.print_field("addr",addr,32);
  printer.print_array_header("data",data.size(),"queue(byte)");
  foreach (data[i])
    printer.print_field($sformatf("[%0d]",i),data[i],8);
  printer.print_array_footer(data.size());
endfunction

endclass

class packet extends packet_base;

`uvm_object_utils(packet)

rand int extra_int;

function new(string name="");
  super.new(name);
endfunction

virtual function void do_pack(uvm_packer packer);
  super.do_pack(packer);
  `uvm_pack_int(extra_int)
endfunction

virtual function void do_unpack(uvm_packer packer);
  super.do_unpack(packer);
  `uvm_unpack_int(extra_int)
endfunction

virtual function string convert2string();
  return $sformatf("%s extra_int:%h",super.convert2string(),extra_int);
endfunction

endclass

endpackage : user_pkg

`include “consumer.sv”

// (begin inline source)
module sv_main;

`include “uvm_macros.svh”
import uvm_pkg::;
import uvmc_pkg::
;
import user_pkg::*;

// Define env with connection specifying custom converter

//sv_env env;
consumer #(packet) cons = new (“cons”);

initial begin
uvmc_tlm #(packet)::connect(cons.in, “stimulus”);
run_test();
end

endmodule


Best Regards,
Shivakumar

In reply to Shivakumar AN:

Shivakumar,

I’ve verified that this bug still exists as of the latest upstream source and
that it is an artifact of how proxy ports inside UVMC on the SV an SC sides are
being attributed in terms of whether they are blocking_transport, non-blocking
forward transport, or non-blocking backward transport. A special mask operation
checks that the appropriate proxy port on one side has the same matching
attribute as the actual port on the other side.

The quick workaround is modify these lines in src/connect/uvmc_common.cpp
in the uvmc_proxy_base::resolve() method,

Index: uvmc_common.cpp

— uvmc_common.cpp (revision 1723)
+++ uvmc_common.cpp (working copy)
@@ -373,7 +373,7 @@
// port, so this proxy must provide the full interface of the SV side proxy.
//
if (proxy->proxy_kind() == UVM_PORT) {

  • if ((proxy->mask() & sv_mask) != sv_mask) {
  • if ((proxy->mask() & sv_mask) == 0) {
    cout << “UVMC-Error: SC-side proxy port for '” << proxy->name()
    << “’ with mask '” << hex << proxy->mask() << dec
    << “’ and id '” << proxy->id()
    @@ -385,7 +385,7 @@
    }
    }
    else {
  • if ((sv_mask & proxy->mask()) != sv_mask) {
  • if ((sv_mask & proxy->mask()) == 0) {
    cout << “UVMC-Error: SC-side proxy channel for '” << proxy->name()
    << “’ with mask '” << hex << proxy->mask() << dec
    << “’ and id '” << proxy->id()

Effectively this workaround slightly relaxes attribute matching check described
above, however, there is more to the fix on the SV side that we still need some
additional internal testing for.

Additionally, I’ve modified the examples/converters/sc_converter_trans.sv,.sc
examples to effectively test transactions in both the SV → SC direction
(as current code does) and the SC → SV direction as your example does.

With the above workaround that seems to be working fine now.

I will e-mail you the modified examples/converters/ area so that you
can see the newly modified example.

I will see to it that this modified example, along with the permanent fix
for this issue gets into the upstream release for the upcoming uvmc-2.3.2
release.

– johnS

In reply to jstickle:

Thanks for the explanation and workaround John.
It worked after modifying src/connect/uvmc_common.cpp locally.
Sure, I will update to latest release once you add the fix to it.


Best Regards,
Shivakumar