Jump to content

Initial value port


DS1701

Recommended Posts

Ports do not hold values. Ports are simply references to channels. Ports provide a means to access a channel.

sc_signal is simply a type of channel. This particular channel supports several methods including read() and write(), which are used to obtain (get) and alter (set) the state (attribute) of the channel.

You can use these methods signal directly:

type value; //< local storage
...
  signal.write( value );
...
  value = signal.read();

Or if the channel is located outside your module, you should access the methods via port connections thus:

output->write( value );
...
value = input->read();

Because the connectivity is not fully established until after elaboration is completed, you generally cannot provide an initial value during construction of an external channel from inside a module. Also, the signal method takes advantage of the update phase of the simulator and should only be accessed at start of simulation.

Therefore, the proper way to initialize a "port" is to write to the corresponding signal a the start of simulation by overriding the so-called callback method start_of_simulation():

SC_MODULE( MyModule )
{
  ...
  void start_of_simulation( void ) override;
};

Implementation:

void MyModule::start_of_simulation( void )
{
  output->write( initial_value );
}

 

Link to comment
Share on other sites

In addition to what David said.

 

Quote

Do you need set Initial value ( use write(0); ) for output and signal port  or it auto set 0 when declare?

Here is what SystemC standard says:

Quote

6.4.5 Constructors
sc_signal();    
explicit sc_signal( const char* name_ );   

Both constructors shall initialize the value of the signal by calling the default constructor for type T from their initializer lists.

So SystemC standard guarantees that signal value is initialized by default constructor. So for example sc_signal<int> is guaranteed to be initialized with 0.

Accellera SystemC also supports passing initial value as a second constructor parameter:

sc_signal<int>  int_signal{"int_signal", 42}; // Initialized to 42

Looks like this feature is not part of IEEE standard yet.

As David noted, ports in SystemC have no value, they behave more like a pointers to channels. So "value" of port always equals to value of binded channel.

 

Link to comment
Share on other sites

Thank @David Black and @Roman Popov

Thank you so much!!!

But I think that, initialize the value depend on specification model require.

Ex:  Model A can reset Model B  with reset port active with LOW level

Then sc_out<bool> resetPort; in the Model A must be set initialize the value for resetPort is 1 on constructor

So I think that , Should set initialize the value of port on constructor

 -->  Clearly

-->  Easy maintain source code

/
//A.h
class A: public sc_module
{

public:
    sc_in<bool>     clkAPM;
    sc_out<bool>    resetPort;
    sc_signal<bool> sig;
...
///A.cpp
A::A(sc_module_name name)
        :sc_module(name)
	    // Initializing
        ,clkAPM("clkAPM")
        ,resetPort("resetPort")
        ,sig("sig")
{//{{{ 
    /// Initializing

    resetPort.initialize(true);
    sig.write(true);

    SC_METHOD(AMethod);
    dont_initialize();
    sensitive << sig ;
...

 

Link to comment
Share on other sites

The 'initialize(T)' method is a leftover from SystemC 1.0 circa 1999, when SystemC had not yet properly abstracted the port/channel concept. At that point in time, there was a stronger emphasis on making SystemC look like Verilog or VHDL. The 'initialize(T)' method is only present on the 'sc_out<T>' and 'sc_inout<T>' port classes, as part of their partial template specialization. The 'initialize(T)' method is not generally available to 'sc_port<>'.

I usually don't mention it because then the reader gets the wrong impression that 'initialize(T)' should be present everywhere. In fact, it is only useful for RTL aspects. Certainly, this is not part of TLM.

Since SystemC is more about abstraction and modeling, I avoid it. It is straightforward to override start_of_simulation.

@TRANGIt is important for you to understand this distinction. I realize that the specification may say that "port is initialized to zero" or some such, but the concept of port in the specification is quite different than the concept of port in SystemC. If you don't understand this, you will hobble your understanding of SystemC. So there are three ways in SystemC of modeling what the specification says regarding an output pin on a hardware design.

  1. Depend on the underlying datatype's initial value to initialize the signal (not very flexible)
  2. If using the specialized ports (sc_out and sc_inout only), call the initialize(T) method.
  3. Write to the port during start_of_simulation, which is the most general and powerful approach.

Challenge: How would you initialize an sc_fifo< float > connected to an sc_fifo< float > channel with four values?

#include <systemc>
#include <list>
#include <iostream>
using namespace sc_core;
using namespace std;
SC_MODULE( Source ) {
  sc_fifo_out< float > send_port;
  SC_CTOR( Source ) {
    SC_THREAD( source_thread );
  }
  void source_thread( void ) {
    wait( 10, SC_NS );
    send_port->write( 99.7 );
    wait( 10, SC_NS );
    std::cout << "Finished" << std::endl;
    sc_stop();
  }
  // How to initialize output to contain following initial values?
  // { 4.2, -8.3e9, 0.0, 3.14 }
  // Do not add this to the thread. Instead, ensure that it happens before any thread executes.
  }
};

SC_MODULE( Sink ) {
  sc_fifo_in< float > receive_port;
  SC_CTOR( Sink ) {
    SC_THREAD( sink_thread );
  };
  void sink_thread( void ) {
    for(;;) {
      std::cout 
        << "Received " << setw(12) << receive_port->read() 
        << " at " << sc_time_stamp() 
        << std::endl;
    }
  }
};

SC_MODULE( Top ) {
  // Constructor
  SC_CTOR( Top ) {
    m_source.send_port .bind( m_fifo );
    m_sink.receive_port.bind( m_fifo );
  }
  // Local modules
  Source           m_source { "source" };
  Sink             m_sink   { "sink"   };
  // Local channels
  sc_fifo< float > m_fifo;
};

int sc_main( int argc, char* argv[] ) {
  Top top { "top" };
  sc_start();
  return 0;
}

Key concepts:

  • SystemC is a modeling language mapped on top of C++.
  • SystemC ports are not signals or pins.
  • sc_in<T>, sc_out<T> and sc_inout<T> are partial template specializations of sc_port<T> on the respective sc_signal<T> interface classes.
  • For historic reasons (SystemC 1.0), there are extra methods added to these specializations including initialize(T), read(), and write(T) that can later confuse novice SystemC programmers.
Link to comment
Share on other sites

On 12/15/2018 at 7:24 PM, David Black said:

The 'initialize(T)' method is a leftover from SystemC 1.0 circa 1999, when SystemC had not yet properly abstracted the port/channel concept. At that point in time, there was a stronger emphasis on making SystemC look like Verilog or VHDL. The 'initialize(T)' method is only present on the 'sc_out<T>' and 'sc_inout<T>' port classes, as part of their partial template specialization. The 'initialize(T)' method is not generally available to 'sc_port<>'.

I usually don't mention it because then the reader gets the wrong impression that 'initialize(T)' should be present everywhere. In fact, it is only useful for RTL aspects. Certainly, this is not part of TLM.

Since SystemC is more about abstraction and modeling, I avoid it. It is straightforward to override start_of_simulation.

@TRANGIt is important for you to understand this distinction. I realize that the specification may say that "port is initialized to zero" or some such, but the concept of port in the specification is quite different than the concept of port in SystemC. If you don't understand this, you will hobble your understanding of SystemC. So there are three ways in SystemC of modeling what the specification says regarding an output pin on a hardware design.

  1. Depend on the underlying datatype's initial value to initialize the signal (not very flexible)
  2. If using the specialized ports (sc_out and sc_inout only), call the initialize(T) method.
  3. Write to the port during start_of_simulation, which is the most general and powerful approach.

Challenge: How would you initialize an sc_fifo< float > connected to an sc_fifo< float > channel with four values?

Key concepts:

  • SystemCis a modeling language mapped on top of C++.
  • SystemC ports are not signals or pins.
  • sc_in<T>, sc_out<T> and sc_inout<T> are partial template specializations of sc_port<T> on the respective sc_signal<T> interface classes.
  • For historic reasons (SystemC 1.0), there are extra methods added to these specializations including initialize(T), read(), and write(T) that can later confuse novice SystemC programmers.

I usually don't use sc_fifo ( only use sc_signal, sc_in, sc_out ). But I don't see any function  initialize the value for sc_fifo . Both "write()" and "nb_write()" (sc_fifo) will call to sc_prim_channel::request_update() . So I think , sc_fifo can set value for buffer ( this isn't called initialize the value forbuffer )

Thank you so much!!! @David Black

Link to comment
Share on other sites

  • 1 month later...

[Sorry for delay. For some reason I was not notified of your reply.]

The point of my challenge was that you would not initialize the FIFO beyond allowing to come up empty. At least I have never see a FIFO that would be pre-filled.

At start_of_simulation, you can initialize all you want as long as you can do everything within a single delta cycle. Hence you can write signals and fffos. Effectively, start_of_simulation is when activity is allowed to start happening.

Link to comment
Share on other sites

  • 6 months later...

I'm reading this thread and successfully tried 'start_of_simulation' and 'initialize', but as I expected, this did not solve my issue.

I want to build a SystemC transactor translating READ/WRITE-TLM to a RAM into RTL "bit wiggles". This part was no problem for me. I implemented a b_transport that is being called by the requesting module and this b_transport is assigning the intended values to my transactor's sc_out (ram_en, ram_rw, ram_addr, ...)

But until the first TLM arrives, the sc_out are not initialized. If I use 'start_of_simulation' or 'initialize' than I create a second driver! One as part of my transactor and one more by the module that is making use of the b_transport. In other words: I cannot override the initial values and receive 'X' where the driven '1' and '0' collide.

My plan is to have b_transport work on dedicated extra signals. My transactor initializes the sc_out (ram_en, ram_rw, ram_addr, ...). I will also implement another method, that shall be sensitive to the extra signals which will be toggled by b_transport. In this method I then assign the values of the signals to the sc_out. This way the driver to sc_out should be the transactor, only.

QUESTIONS:
Does it really have to be such a pain to implement a transactor by making use of such a mentioned method in between? And I did not try it yet, but I guess this should work?

Link to comment
Share on other sites

4 hours ago, Frank Poppen said:

But until the first TLM arrives, the sc_out are not initialized. If I use 'start_of_simulation' or 'initialize' than I create a second driver! One as part of my transactor and one more by the module that is making use of the b_transport. In other words: I cannot override the initial values and receive 'X' where the driven '1' and '0' collide.

Won't you have multiple drivers anyway as soon as you have a second initiator accessing your transactor?

I would recommend to switch your pin interface to use sc_export<sc_signal_*_if<T> > instead of plain signal ports and bind signals with an SC_MANY_WRITERS policy internally.  These signals also have constructors that allow initialization to a non-zero value without triggering an event at the start of simulation.

Link to comment
Share on other sites

I always change default policy to SC_MANY_WRITERS. In commercial simulators usually there is also a way to change default policy.

In verification environments default SC_ONE_WRITER policy is violated way too often. It also does not work well with FORK/JOIN, when you spawn different threads in each test to generate  stimulus on same set of ports. 

 

Link to comment
Share on other sites

Changing the default writer policy requires to be set consistently throughout the whole application, which might be difficult with third-party infeeds.

Since SystemC 2.3.2, you can also set the environment variable SC_SIGNAL_WRITE_CHECK=CONFLICT, which effectively enables SC_MANY_WRITERS at runtime (for all signals, though). Quoting the release notes:

  - [2.3.2] Add support for SC_SIGNAL_WRITE_CHECK=CONFLICT

    Instead of disabling all runtime signal write checks via the
    environment setting SC_SIGNAL_WRITE_CHECK=DISABLE, setting the
    variable to SC_SIGNAL_WRITE_CHECK=CONFLICT allows detecting
    conflicting writes to a signal within a single evaluation phase
    (see INSTALL).

 

Link to comment
Share on other sites

  • 2 weeks later...
On 7/24/2019 at 3:17 PM, Philipp A Hartmann said:

Won't you have multiple drivers anyway as soon as you have a second initiator accessing your transactor?

Oh, ... right I guess that would be true. Luckily, in my scenario I have just one initiator. Under this circumstances I was able to help myself with the second set of signals and the method inbetween as mentioned above. For the time being I will leave it the way it is.

Once multiple initiators start to be relevant in our case I will definitely come back to your recommandation. Thanks for the help!

Link to comment
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...