Giuli0

Channel vs port value update

6 posts in this topic

Hello everybody,

While working on a systemC project, I discovered that probably I have some confused ideas about signals and ports. Let's say I have something like this:

 

//cell.hpp

SC_MODULE(Cell)

   sc_in<sc_uint<16> > datain; 
   sc_in<sc_uint<1> > addr_en;
   sc_in<sc_uint<1> >  enable;
   sc_out<sc_uint<16> > dataout;
  
   SC_CTOR(Cell)
   {
     SC_THREAD(memory_cell);
        sensitive << enable << datain << addr_en;
   }
   private:
   void memory_cell();
};

 

//cell.cpp

void Cell::memory_cell()
{  
   unsigned short data_cell=11;
        
   while(true)
   {     
      //wait for some input
      wait();     
           
      if (enable->read()==1 && addr_en->read()==1)
      {        
         data_cell=datain->read();        
      }
      
      else
      {
         if(enable->read()==0 && addr_en->read()==1)
         {
            dataout->write(data_cell);
         }
     }
   }
}

 

 

//test.cpp

SC_MODULE(TestBench)
{
   sc_signal<sc_uint<1> > address_en_s;
   sc_signal<sc_uint<16> > datain_s;  
   sc_signal<sc_uint<1> >  enable_s;
   sc_signal<sc_uint<16> > dataout_s;   
    
   Cell cella;
   
   SC_CTOR(TestBench) : cella("cella")
   {
        // Binding
        cella.addr_en(address_en_s);
        cella.datain(datain_s);
        cella.enable(enable_s);
        cella.dataout(dataout_s);               
        SC_THREAD(stimulus_thread);                        
   }


  private:
    void stimulus_thread() {  

//write a value:    
        datain_s.write(81);    
        address_en_s.write(1);    
        enable_s.write(1);         
        wait(SC_ZERO_TIME);
       

//read what we have written:
        enable_s.write(0);
        address_en_s.write(1);
        wait(SC_ZERO_TIME);
                 
        cout << "Output value: " << dataout_s.read() << endl;
        

//let's cycle the memory again:       
        address_en_s.write(0);         
        wait(SC_ZERO_TIME);
        cout << "Output value: " << dataout_s.read() << endl;
       
    }   
};

 

 

I've tried running this modules and I've noticed something weird (at least, weird for me): when the stimulus writes a value (81), after the wait(SC_ZERO_TIME) the memory thread finds its datain, enable and address_enable values already updated. This is what I expected to happen. The same happens when the stimulus changes the enable_es value, in order to run another cycle in the memory thread and copy the datacell value into the memory cell dataout port. What I don't understand is why after the memory module writes into its dataout port and goes again to the wait() statement at the beginning of the while loop, the stimulus module still has the old value on its dataout_s channel (0), and not the new value(81), which has just been copied by the memory module. Then, if I run another cycle of the memory loop (for example changing some values on the stimulus channels), the dataout channel finnally updates.

In other words, it looks like that if I write into the stimulus channels and then switch to the memory thread, the memory finds the values updated. But if the memory thread writes into its ports, and then i switch to the stimulus thread, the thread still sees the old values on its channels (binded to the memory ports).

 

I don't know if I am clear, and I am sure that maybe this is a naive question, but i am a newbie with systemC and I need to understand this thing.

 

 

 

 

Share this post


Link to post
Share on other sites

Try changing,

//read what we have written:
   enable_s.write(0);
   address_en_s.write(1);
   wait(SC_ZERO_TIME);
                 
   cout << "Output value: " << dataout_s.read() << endl;

To,

//read what we have written:
   enable_s.write(0);
   address_en_s.write(1);
   wait(SC_ZERO_TIME);
   wait(SC_ZERO_TIME);
                 
   cout << "Output value: " << dataout_s.read() << endl;

This is not the recommended solution! But only a step towards debugging the problem.

 

Also, print the return value of sc_time_stamp() and sc_delta_count() in memory thread after wait(), and in the stimulus thread after each wait(SC_ZERO_TIME).

Share this post


Link to post
Share on other sites

Hi.

 

Short answer: going through two signals means two delta cycles, sc_wait(SC_ZERO_TIME) waits for one delta cycle.

 

When you write to a signal, you can read the new value in the next delta cycle. 

sc_wait(SC_ZERO_TIME) waits for exactly one delta cycle. 

 

What happens here is: 

delta 0:

tb: write (81,1,1) to the signals, then wait for next delta

cell: init data_cell to 11, then wait

 

delta 1:

tb: write (0,1) to the signals, then wait for next delta

cell: triggered by tb write in previous delta, read data_in

 

delta 2:

tb: cout data_out (should be initial value), write 0 to addr_en, then wait for next delta

cell: triggered by tb write in previous delta, write dataout

 

delta 3:

tb: cout dataout (should be new value now, written in last delta)

cell: triggered by tb write in previous delta, no action because of 'if'

 

in general, it might be a good idea to separate stimulus and monitor: Use a different thread (or method) sensitive to dataout that prints every value change of dataout (together with time_stamp and delta_count as mentioned by Karthick Gururaj.

 

Greetings

Ralph

Share this post


Link to post
Share on other sites

Try changing,

//read what we have written:
   enable_s.write(0);
   address_en_s.write(1);
   wait(SC_ZERO_TIME);
                 
   cout << "Output value: " << dataout_s.read() << endl;

To,

//read what we have written:
   enable_s.write(0);
   address_en_s.write(1);
   wait(SC_ZERO_TIME);
   wait(SC_ZERO_TIME);
                 
   cout << "Output value: " << dataout_s.read() << endl;

This is not the recommended solution! But only a step towards debugging the problem.

 

Also, print the return value of sc_time_stamp() and sc_delta_count() in memory thread after wait(), and in the stimulus thread after each wait(SC_ZERO_TIME).

 

Thanks Karthick, now it works, but I am not sure why!

Using you suggestion, generally speaking I think that the mechanism works like this:

If I write something in threadA during delta number 1, it will only be available in threadB during delta num2. And if deltaB writes something during its delta num2, threadA has to wait delta num3 in order to read it.

 

This is why the stimulus thread needs 2 wait(SC_ZERO_TIME) statements in order to read the correct output from the memory, because it has to forward its delta value.

Am I right?

 

And if all of this is right, what could be a more reccomended solution, instead of using two wait statements?

Share this post


Link to post
Share on other sites

Hello Ralph,

I was trying and answering to Karthick and I didn't see your answer. After reading it, I guess I was right.

ThreadA and threadB are connected through a signal. ThreadA writes on the signal during its delta numb1, and this value will be seen by threadB only during its delta number2. Right?

 

Thanks you both Karthick and Ralph!

Share this post


Link to post
Share on other sites

Yes. But it is independent from threads. Its a property of signals with delta cycle semantics. 

If you change the value of a signal by writing to it, you will read the old value until the next update phase in the simulation (which is in fact the beginning of the next delta cycle). It does not matter wether you are in the same tread or not. In the update phase, you get both: The value changes to the new one and the event according the the value change sets all processes sensitive to this event to 'runnable'.

 

Greetings 

Ralph

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now