Jump to content
jserot

Tracing custom channels

Recommended Posts

Dear all,

 

I'm implementing a custom channel which is basically an hybrid object, offering a fifo-lile interface on the reader side and a signal-like interface on the writer side. The code is given below (listing 1). Basically, it just wraps up a sc_signal so that it can be viewed as a never-empty FIFO on the reader side.

 

It works well except that the value changes -- that are correctly witnessed by issuing print msg in the write() method() -- are not dumped in the trace file (see listing 2).

 

My intuition is that the write actions are not viewed by the trace mechanism and that i should explicitly call a method for this in the write() method. 

But i can just figure out which one. I've browsed the ref man but cannot find the answer to this question : what events are exactly dumped in the trace file when a channel is registered as traced by calling sc_trace ?

 

Any clue ?

 

Jocelyn

template<class T>
class buffer_in
: public sc_signal_write_if<T>,
  public fifo_in_if<T>,
  public sc_prim_channel
{
protected:
  sc_signal<T> m_sig; 
  sc_event m_data_written_event;
public:
  explicit buffer_in( const char* name_ ) :
      m_sig(name_),
	  m_data_written_event((std::string(SC_KERNEL_EVENT_PREFIX)+"_write_event").c_str()) { }

  virtual ~buffer_in() { }

  // (read-only) fifo-conformant interface
  virtual int num_available() const { return 1; }
  virtual void read( T& t) { t = m_sig.read(); }
  virtual T read() { return  m_sig.read(); }
  virtual bool nb_read( T& t) { t = m_sig.read(); return true; }
  virtual const sc_event& data_written_event() const { return m_data_written_event; }
  virtual T peek() const { return m_sig.read(); }
  virtual bool rd_rdy() const { return 1; }

  // (write-only) signal-conformant interface
  virtual void write( const T& t) {
    cout << "*** *** buffer " << m_sig.name() << " : write: " << t << endl; cout.flush();
    m_data_written_event.notify(SC_ZERO_TIME); m_sig.write(t); };

  // other methods
  virtual const char* kind() const { return "buffer_in"; }
  operator T () { return read(); }
  void trace( sc_trace_file* tf ) const { m_sig.trace(tf); } // sc_trace( tf, m_sig.read(), name()); }
};

int sc_main(int argc, char* argv[]) {
  sc_clock clk("clk", 10, SC_NS, 1);
  sc_trace_file *trace_file;
  trace_file = sc_create_vcd_trace_file ("test_buffer");
  ...
  buffer_in<sc_uint<8> > w("b1");
  ...
  sc_trace(trace_file, clk, "clk");
  sc_trace(trace_file, w, "b1");
  sc_start(100, SC_NS);
  sc_close_vcd_trace_file (trace_file);
  cout << "Wrote file test_buffer.vcd" << endl;
  return EXIT_SUCCESS;
}

Share this post


Link to post
Share on other sites
protected:
sc_signal<T> m_sig;
sc_event m_data_written_event;

public:
explicit buffer_in( const char* name_ ) :
m_sig(name_),
     m_data_written_event((std::string(SC_KERNEL_EVENT_PREFIX)+"_write_event").c_str()) { }

Your problem is possibly  you are trying to trace event. sc_event(s) are not tracable. 

 

By the way std::string(SC_KERNEL_EVENT_PREFIX) will add some horrible $$$$ .....

Share this post


Link to post
Share on other sites

If you want to trace a user defined data type, you have to write an overloaded sc_trace function for that type.

So if you wanted to trace your type you'd have to write a non-member function

 

template<T>

sc_trace(sc_trace_file *, const sc_buffer_in<T>, const std::string& );

 

and then in that function call sc_trace for the member m_sig.

 

The standard says (in 8.2.1)

"All changes to the value of the second argument that occur between the time the function is called and
the time the trace file is closed shall be recorded in the trace file."

 

 

regards

Alan

Share this post


Link to post
Share on other sites

 

Dear all,

 

I'm implementing a custom channel which is basically an hybrid object, offering a fifo-lile interface on the reader side and a signal-like interface on the writer side. The code is given below (listing 1). Basically, it just wraps up a sc_signal so that it can be viewed as a never-empty FIFO on the reader side.

 

It works well except that the value changes -- that are correctly witnessed by issuing print msg in the write() method() -- are not dumped in the trace file (see listing 2).

 

My intuition is that the write actions are not viewed by the trace mechanism and that i should explicitly call a method for this in the write() method. 

But i can just figure out which one. I've browsed the ref man but cannot find the answer to this question : what events are exactly dumped in the trace file when a channel is registered as traced by calling sc_trace ?

 

Any clue ?

 

Jocelyn

template<class T>
class buffer_in
: public sc_signal_write_if<T>,
  public fifo_in_if<T>,
  public sc_prim_channel
{
protected:
  sc_signal<T> m_sig; 
  sc_event m_data_written_event;
public:
  explicit buffer_in( const char* name_ ) :
      m_sig(name_),
	  m_data_written_event((std::string(SC_KERNEL_EVENT_PREFIX)+"_write_event").c_str()) { }

  virtual ~buffer_in() { }

  // (read-only) fifo-conformant interface
  virtual int num_available() const { return 1; }
  virtual void read( T& t) { t = m_sig.read(); }
  virtual T read() { return  m_sig.read(); }
  virtual bool nb_read( T& t) { t = m_sig.read(); return true; }
  virtual const sc_event& data_written_event() const { return m_data_written_event; }
  virtual T peek() const { return m_sig.read(); }
  virtual bool rd_rdy() const { return 1; }

  // (write-only) signal-conformant interface
  virtual void write( const T& t) {
    cout << "*** *** buffer " << m_sig.name() << " : write: " << t << endl; cout.flush();
    m_data_written_event.notify(SC_ZERO_TIME); m_sig.write(t); };

  // other methods
  virtual const char* kind() const { return "buffer_in"; }
  operator T () { return read(); }
  void trace( sc_trace_file* tf ) const { m_sig.trace(tf); } // sc_trace( tf, m_sig.read(), name()); }
};

int sc_main(int argc, char* argv[]) {
  sc_clock clk("clk", 10, SC_NS, 1);
  sc_trace_file *trace_file;
  trace_file = sc_create_vcd_trace_file ("test_buffer");
  ...
  buffer_in<sc_uint<8> > w("b1");
  ...
  sc_trace(trace_file, clk, "clk");
  sc_trace(trace_file, w, "b1");
  sc_start(100, SC_NS);
  sc_close_vcd_trace_file (trace_file);
  cout << "Wrote file test_buffer.vcd" << endl;
  return EXIT_SUCCESS;
}

 

Hello,

After reading through your code, here are a few

questions: As your custom channel is is going to

transfer some generic type 'T', it will depend very

much on whether what the actual type of 'T' is, in

order for 'cout' to print out something meaningful.

To be specific, if for example T is a bit vector or

even a string, there would be no issues. But if T

is itself another object, say a struct with different

types of data inside it, then these need to be

printed out separately. 

This is subtle problem with C++ templates in

general - although they represent "generic"

data types, often times manipulating these 

generic data types involve using plain good

old C style techniques and tricks. Hope that

helps.

Share this post


Link to post
Share on other sites

Dear all,

 

Thank for your answers.

 

 

Your problem is possibly  you are trying to trace event. sc_event(s) are not tracable. 

 

By the way std::string(SC_KERNEL_EVENT_PREFIX) will add some horrible $$$$ .....

 

 

Sorry, i dont understand. What i'm trying to do is to trace value change on a signal - there surely must be a way to do this since tracing a sc_signal is obviously possible..

For the SC_KERNEL_EVENT_PREFIX, you're right, i can probably get rid of this (i just copied this line from the sc_fifo.h..)

 

 

If you want to trace a user defined data type, you have to write an overloaded sc_trace function for that type.

So if you wanted to trace your type you'd have to write a non-member function

 

template<T>

sc_trace(sc_trace_file *, const sc_buffer_in<T>, const std::string& );

 

and then in that function call sc_trace for the member m_sig.

 

The standard says (in 8.2.1)

"All changes to the value of the second argument that occur between the time the function is called and
the time the trace file is closed shall be recorded in the trace file."

 

 

regards

Alan

 

Thanks for the suggestion, Alan.
I tried this, adding this definition after the buffer_in class definition in my .h file (incidentally, i had to make the m_sig member public for this) : 

template<class T>
void sc_trace(sc_trace_file *tf, const buffer_in<T> b, const std::string& s)
{
   sc_trace( tf, b.m_sig, s);
}

but i get this error msg from the C++ compiler :

In file included from test_buffer_port_in.cpp:5:
../buffer_in.h:14:7: error: inherited virtual base class 'sc_core::sc_interface' has private copy constructor
class buffer_in
      ^
/usr/local/systemc-2.3.0/include/sysc/communication/sc_interface.h:65:5: note: declared private here
    sc_interface( const sc_interface& );

Seems i'm bumping again against a complex inheritance pb :-(

 

 

Hello,

After reading through your code, here are a few

questions: As your custom channel is is going to

transfer some generic type 'T', it will depend very

much on whether what the actual type of 'T' is, in

order for 'cout' to print out something meaningful.

To be specific, if for example T is a bit vector or

even a string, there would be no issues. But if T

is itself another object, say a struct with different

types of data inside it, then these need to be

printed out separately. 

This is subtle problem with C++ templates in

general - although they represent "generic"

data types, often times manipulating these 

generic data types involve using plain good

old C style techniques and tricks. Hope that

helps.

 

I understand this and all the types T that will be used to parameterize my buffer_in class are indeed equiped with the necessary functions to be traced..

In fact, i'm really puzzled by the fact that a similar class, buffer_out (see listing below) works perfectly well as regards tracing. I'm wondering what makes the difference with the above-mentionned buffer_in class..
 

template<class T>
class buffer_out
: public fifo_out_if<T>,
  public sc_signal_in_if<T>,
  public sc_prim_channel
{
protected:
  const char *name;
  sc_signal<T> m_sig; 
  sc_event m_data_read_event;

public:
  explicit buffer_out(const char* name_) :
      name(name_),
      m_sig(name_),
	  m_data_read_event((std::string(SC_KERNEL_EVENT_PREFIX)+"_read_event").c_str())
      {}

  virtual ~buffer_out() { }

  // fifo-like interface
  virtual int num_free() const { return 1; }
  virtual void write( const T& v) {  m_sig.write(v); }
  virtual bool nb_write(const T& t) { m_sig.write(t); return true; };
  virtual bool wr_rdy() const { return true; }
  virtual const sc_event& data_read_event() const { return m_data_read_event; }

  // signal-conformant interface
  virtual const sc_event& value_changed_event() const { return m_sig.value_changed_event(); }
  virtual const T& read() const { /*m_data_read_event.notify(SC_ZERO_TIME);*/ return m_sig.read(); }
  virtual const T& get_data_ref() const { return m_sig.get_data_ref(); }
  virtual bool event() const { return m_sig.event(); }

  // other methods
  virtual const char* kind() const { return "buffer_out"; }
  buffer_out<T>& operator = ( const T& a ) { write(a); return *this; }
  void trace( sc_trace_file* tf ) const { sc_trace(tf, m_sig.read(), m_sig.name()); };
  // THIS WORKS. All write events get actually logged in the trace file.. 
 };

Share this post


Link to post
Share on other sites

Hi Jocelyn,

 

 I think the reason the buffer_out works is that the trace function you are calling is declared in sc_signal_in_if, but isn't part of sc_signal_write_if.

 

However using that trace is "cheating" because it's not part of the public API defined in the standard. Of course it does work with the Accellera Proof of Concept simulator.

 

Regarding the copy constructor error, that's my fault - you need to declare the sc_trace function to take a const ref to the buffer_in, not a const object - because it's an object not a ref, it's invoking the copy constructor when the sc_trace is called, and  as you've found some of the base class copy constructors are intentionally disabled.

 

So change the function declaration to

 

sc_trace(sc_trace_file *, const buffer_in<T> &, const std::string &);

 

regards

Alan

Edited by apfitch

Share this post


Link to post
Share on other sites

So change the function declaration to

 

sc_trace(sc_trace_file *, const buffer_in<T> &, const std::string &);

 

regards

Alan

 

Ok; i should have spotted this myself ;-)

 

Now it works correctly.

 

Thanks _a lot_ for your help !

 

Best wishes

 

Jocelyn

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...