Jump to content

jserot

Members
  • Content Count

    16
  • Joined

  • Last visited

Posts posted by jserot


  1. 11 hours ago, Roman Popov said:
    Quote

    Essentially it will be sc_fifo with immediate notification and capacity  == 1.  If consumer reads from empty fifo it will be blocked until producer writes into fifo. With immediate notification it will be resumed in the same delta cycle as producer writes into fifo. 

    The consumer should never block in my case. Reading twice a shared variable which has only been written once should not block the reader...

     

     


  2. 11 hours ago, Roman Popov said:
    Quote

     

    Ok, understood.

    Yes, the only way to execute this in a single delta cycle is to enforce execution order using events with immediate notification. It is impossible to implement it in other way in C++.


     

    Ok, thanks. This is indeed what i suspected.

    Quote

     

    What you want is a “SystemC-language-aware” compiler. Such a compiler will need to understand a semantics of processes and create a static schedule: such as a producer processes are always executed before consumer processes.


     

    Exactly. In fact, this is the kind of  solution i'm investigating. I'm starting from a compiler internal representation of the application as a graph of FSMs connected via shared variables. Each FSM is implemented as a SystemC module. The idea is to extract from the graph the chain of dependencies - i.e. which module(s) read (resp. write) each variable - and to insert delta wait(s) at the right place(s). In the example above, this would involve rewriting B as 

    
    void B::my_thread()
    {
      while ( 1 ) {
        wait(h.posedge_event());
        wait(SC_ZERO_CYCLE);
        if ( v == 1 ) xxx;
        ...
        }
    };
    Quote

    Static scheduling is not always possible, because some processes can have cyclic data dependencies. So as you’ve said, sometimes it will need to resolve <<undeterminacy by iterating  until a fix-point is reached>>

    Cyclic dependencies can be detected statically (as loops in the graph) and the corresponding programs rejected i guess.

     


  3. Hi Roman, thanks for your feedback.

    Instantaneous broadcast - also called "perfect synchrony" - means that any update performed to a shared value by a component (a module in our case) will be viewed immediately by other components (and not after n delta cycles, as for sc_signals). 


    Here's a typical example, with two modules :

    - module A waits for (global) event H (a clock typically) and, when received, set shared variable v  to 1

    - module B also waits for H but when received only performs action xxx if v=1 (in StateChart, this is called a guarded transition)

    void A::my_thread()
    {
      ...
      while ( 1 ) {
        ...
        wait(h.posedge_event());
        v = 1;
        ...
        }
    };
    
    void B::my_thread()
    {
      while ( 1 ) {
        wait(h.posedge_event());
        if ( v == 1 ) xxx;
        ...
        }
    };

    As explained by Alan, the above implementation does not correspond to the behavior suggested above :

    - if v is implemented by using a sc_signal, then v only takes value 1 at time t+delta (if H occurs at time t), and hence "too late" for B

    - if v is implemented as a "regular" shared variable, then  the behavior becomes non-deterministic (whether B "sees" v=1 depends on the order at which the scheduler runs the corresponding threads, which is un-predictable).

    Currently, I don't see a solution other than enforcing execution order using sc_events (as suggested by Alan). But this seriously complicates the translation from formalisms supporting the SB hypothesis to SystemC. I was just wondering if i was missing sth about SystemC semantics or whether this  was simply not possible..

    Jocelyn

     


  4. Hi,

    Sorry for resurrecting this post but it addresses an issue i'm currently facing.

    Does this mean that it is not possible  to implement instantaneous broadcast (as used in StateCharts or synchronous reactive models of computation for ex.) in SystemC ? With the latters, the undeterminacy is resolved by iterating  until a fix-point is reached so that the final values of shared variables do not depend on the order of (micro)-steps ? 


    Jocelyn


  5. 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.. 
     };
    
    

  6. 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;
    }
    
    

  7. This is exactly what i've been doing up to now !

    But since my specific fifo is very similar to the sc_fifo, this implies a lot of copying. 

     

    This is that copying I was wishing to avoid by using inheritance. 
    I've read a bit on multiple inheritance issues since yesterday (since i'm not basically a C++ specialist..) : not trivial ones, apparently !

     

    Thanks for the feedback anyway


  8. Thanks a lot  for the tip, Philipp. 

    I haven't thought about this since i'm not familiar with the TLM layer.

    Will try !

     

    This said, i find it awkward that the sc_fifo class cannot be easily extended. Is it a consequence of the limitations of the C++ inheritance mechanism or a deliberate choice of the SystemC designer ?

     

    Jocelyn


  9. Hi,

     

    I reactivate this thread because I've stumbled on the same problem recently and can't seem to find any answer after having crawled the web for a while.

    I understand the pb with the second solution and tried the one given by Philipp (wrapping a sc_fifo instance inside my special fifo class).

    Unfortunately, it does not work if the "derived" (wrapping) class needs to access non-public members of the wrapped class.

    In my case, i wand to add a method 

     

      virtual T peek(void);
     
    which simply returns the data at the top of the FIFO without popping it (non destructive read).

    There's no way to do this using the public interface of the sc_fifo class. The only solution would be to define peek as :
     
      virtual T peek(void) { return p_fifo.m_buf[p_fifo.m_ri]; }
     
    But, as said before, this simply does not work because m_buf and m_ri are _protected_ members of the sc_fifo class.

    So far, the only solution i've found is copy-pasting the code of sc_fifo and adding the requested method, which obviously is a hack.

    Any idea ? 
     
    Thanks in advance.
     
    Jocelyn
     
     

  10. Philip,

    The type inference phase is carried out on a backend-independant representation.

    In this particular case, the tricky thing to do is to map the types computed at this level to SystemC types because, as you rightly puts it, there a significant number of corner cases (and the VHDL backend is even worst..).

    The solution you suggest (inserting unary + or equiv) will unfortunately not work in all cases, because _any kind_ of expression can appear as an argument of the ternary cond operator (sorry, it's difficult to be more explicit w/o showing the intermediate representation and associated transfo rules which are written ... in OCaml ;))

    Thanks anyway for your clever comments and suggestions !

    Jocelyn


  11. Thanks a lot Philipp !

    I was suspecting sth like this but was not aware doing arithmetic on one operand was actually changing its type (compared to the other one).

    In fact, i had searched the sc_int class for an (overloaded) version of the arithm operators (+, _, ...) and was a bit puzzled not to find them.

    Anyway, this explains the problem.

    ... but incidently, does not simplify my life - since the code in question is actually not written by hand but generated by a compiler (more details on this here, in case you would be interested : http://dream.univ-bpclermont.fr/index.php/en/softmenu/caph.html). So this means that i will have to detect and correct these situations on a ad-hoc, type-based, basis :-S

    Thanks again for your help

    Best wishes

    Jocelyn


  12. Thanks for your reply.

    Sorry. My code was confusing. Of course, when compiling, i comment out one of the two lines containing the return statement.

    To be clearer :

    This compiles ok :

    template<int n>

    sc_int<n> f_abs(sc_int<n> x) {

    if ( x <0 ) return 0-x; else return x;

    };

    But this fails to compile :

    template<int n>

    sc_int<n> f_abs(sc_int<n> x) {

    return x<0 ? 0-x : x;

    };


  13. Hi,

    I just stumbled on this.

    The first form (with an "if") compiles ok.

    The second one (with the "?:") fails with this message :

    g++ -Wall -I. -I/Library/SystemC/systemc-2.3.0/include -Wno-deprecated -c -o foo.o foo.cpp

    foo.cpp: In function 'sc_dt::sc_int<n> f_abs(sc_dt::sc_int<n>) [with int n = 8]':

    foo.cpp:14: instantiated from here

    foo.cpp:9: error: operands to ?: have different types

    make: *** [foo.o] Error 1

    Could this be a bug ?

    Any help will be appreciated.

    Thanks in advance.

    Jocelyn

    ------ START of CODE SAMPLE --------

    #define SC_INCLUDE_FX

    #include <systemc.h>

    template<int n>

    sc_int<n> f_abs(sc_int<n> x) {

    if ( x <0 ) return 0-x; else return x; // OK :-)

    return x<0 ? 0-x : x; // NOK :-(

    };

    int sc_main (int argc , char *argv[]) {

    sc_int<8> x=2, y=-3;

    cout << "abs(" << x << ")=" << f_abs(x) << endl;

    cout << "abs(" << y << ")=" << f_abs(y) << endl;

    return 0;

    }

    ------ END of CODE SAMPLE ----------

×
×
  • Create New...