Jump to content

Philipp A Hartmann

Members
  • Posts

    547
  • Joined

  • Last visited

  • Days Won

    135

Posts posted by Philipp A Hartmann

  1. sc_link_mp, sc_inslave, sc_outmaster are elements of the old "SystemC Master-Slave library".  This library has been an early approach to transaction-level modeling in SystemC.  The original implementation will most likely not compile with IEEE 1666-20xx standard-compliant simulators.

     

    For high-level modeling, you should look into the TLM-1 and TLM-2 APIs, that are now part of the IEEE standard for SystemC.

     

    /Philipp

  2. I would use the clock generator coming with SystemC by instantiating an sc_clock (see Section 6.7 in IEEE 1666-2011):

    sc_clock clk( "clk"               // name
                , sc_time(100, SC_NS) // period
                , 0.5                 // duty cycle
                , sc_time(100, SC_NS) // start time
                , true );             // start with positive edge
    

    I've selected the parameters guessing from your code snippet.  In "your" code, the first rising edge seems to occur at 100ns (start time).  Play with the values as you need them.

     

    You can then bind this clock to any sc_in<bool> port in your system.

     

    /Philipp

  3. SC_ON, SC_OFF are related to "floating-point cast switches". You likely don't need to worry about these, if you don't know what problems these intend to address.  Otherwise, please refer to Sections 7.10.7, 711.5 of IEEE 1666-2011.

     

    Syntaxwise, you currently try to invoke the function call operator on the sc_ufixed variable d (with an incompatible parameter).
    What do you intend to achieve?  Do you want to assign a value?

     

    /Philipp

  4. As the original error message says, you are not supposed to disable() a process that is within a timed wait (i.e. wait(xx,SC_NS); in your case).  See Section 5.6.6.2 of IEEE 1666-2011.

     

    Moreover, since your func2 process has no static sensitivity, the process will not run again after it is enabled, unless it is explicitly reset.
    See 5.6.6.2 again, quoting:

     

    If a time-out occurs while a process instance is disabled and that process instance is sensitive to no other events aside from the time-out itself, the process instance will not run again (unless it is reset) and the implementation may issue a warning.

     

    If you want to enable/disable a process, the target process should be sensitive to events, instead of using timed waits itself.

     

    /Philipp

  5. Although Cygwin is not among the most widely tested platforms for the Accellera SystemC proof-of-concept simulator, the current version 2.3.1 has been tested successfully on

    • Windows 7 SP1 (WoW64), (Cygwin 1.7.17)
      • GNU C++ compiler versions gcc-3.4.4 through gcc-4.3.4 (x86)

    Please provide at least

    • SystemC version
    • platform (version), compiler (version), flags
    • compile/runtime warnings and errors

    AFAIK, the _WIN32 macro tells that you're using the Windows API.  Using the Windows API implies that you have support for __int64 and the like.

    Do you define _WIN32 explicitly on the command-line?  Why?  Cygwin does not provide this symbol by default.

     

    Greetings from Oldenburg,
      Philipp

  6. It's called "direct memory interface", because it's a direct access to a target's memory range.  The target has no way to observe accesses from initiators to the currently allowed DMI ranges.  If the target requires to observe such accesses, you should not grant DMI access for these address ranges during the relevant communication states/phases.  Usually, DMI is preferred for the plain memory parts of the target's interface, while (control) registers often require explicit TLM transactions for that reason.

     

    hth,
    Philipp

  7. Your NOC module has indeed many signals.  Hopefully, they are already organized as arrays, which you can replace by using appropriate sc_vectors, which can take an explicit name (prefix).  As a general recommendation, you should consider to give your channels an explicit name to ease debugging of such errors.

     

    A simpler solution is probably to look at the two processes (txProcess, rxProcess) in your Router module.  If the problem would be the duplicate binding of a single signal to multiple output ports, the error should have been reported during elaboration already.  Instead, the error is raised during simulation, where both processes try to write to the same signal, most likely through the same (in)out port. This should be local enough to find manually.

     

    hth,
      Philipp

  8. Yes it is clear from the LRM but I am looking for some mechanism to use similar things in my model which is based on tlm_initiator_socket/tlm_traget_socket.

    I need to know at run time on whcih port the b_transport is called.

    Is it possible ?

     

    If you bind the same interface object (a "single" b_transport) to both target sockets, there is no predefined way to determine the port through which the interface has been called.

     

    If you insist on using a plain tlm_target_socket instead of the tagged convenience sockets, you can build the tagging mechanism on your own by implementing a small helper that provides the forward interface (most notably b_transport), stores an ID internally and forwards the call including the ID to the module itself.  Not sure, why you would need to reinvent that, though.

     

    /Philipp

  9. bool HCE_register::behavior_after_write(uint32_t data){
           sc_event e_HCE;          // <-- strange
           if(data==0x01)
             return e_HCE.notify(); // <-- error
           else
             return 0;
     }
    

     

    The error is caused by the fact that the notify() function of sc_event returns nothing (i.e. 'void').

    So you can't return the (non-existing) return value in the marked line above.

     

    Secondly, e_HCE is a local variable.  You won't be able to trigger any other process by notifying this event.  This looks wrong as well.

     

    /Philipp

  10. My question is in the following code, is the process process1 is static or dynamic process ?

     

    Why don't you ask the process itself?

     std::cout << std::boolalpha << h1.dynamic() << std::endl;
    

    Short answer: Processes created from the process macros SC_THREAD,... are called "unspawned" processes, whereas processes created by sc_spawn are called (surprise!) spawned processes. Unspawned processes are by definition static processes, as the macros can't be used during simulation.  On the other hand, spawned processes can be either static or dynamic processes:

     

    A dynamic process is created during simulation, whereas a static process is created during elaboration.

     

    hth,

    Philipp

  11. I try to define a sc_vector like this in SC_MODULE

     

    sc_vector<sc_signal<sc_uint<C_WIDTH> > > sDin("sDin", C_SIZE);

     

    Your problem is not specific to sc_vector, but to C++ in general: You can't initialize a member of an SC_MODULE (or any other C++ class) in the body of the class itself.  You need to do it in the constructor, using an initializer list:

     

    SC_MODULE(mod)
    {
      sc_vector<sc_signal<sc_uint<C_WIDTH> > > sDin; 
      SC_CTOR(mod)
        : sDin("sDin", C_SIZE) // C++ initializer list
      {
        // ...
      }
    };
    
    Greetings from Oldenburg,

      Philipp

  12. There is no error when adding the line after sc_start, so you may be right.  Skipping the sc_start results in no segfault.

     Ok, the next step could be to skip simulation and just run the elaboration/initialization via

    sc_start( SC_ZERO_TIME );

    Secondly, you should break on the destructor of mod in the debugger to check whether you can see any indication why the destructor is called twice for the same object.  If you have a memory corruption, this might be more difficult to track down.

     

    Moving your line to before the call to sc_start, then debugging, shows something new.

    ...

    GDB then points to the function in mod that uses this to wait on an event from any of the input ports.

    This looks unrelated and is probably caused by accessing unbound ports too early.

     

    Apologies for the delay in putting up a minimal example.  This system is huge and, unfortunately, the mod is at the center of it.  I'm trying to find a way to isolate it and still get something illustrative -- putting up the whole thing is not possible due to an NDA that prevents sharing.

     

    Edit: I should probably add, SystemC 2.3.1.

     

    For now, I think it's more likely that the problem is in your model rather than that there is a bug in SystemC 2.3.1. The sc_vector code didn't change much between 2.3.0 and 2.3.1.

     

    I have added to the playground.  Not getting segfault in the simplified model, but getting another unexpected result.  Data seems to be constructed, but I don't generate data anywhere.  I'm obviously overlooking something basic.  The problem seems to be in the type that I'm passing between modules.

     

    This also sounds like an unrelated problem.  Good luck in the bug hunting.  Feel free to share/post your simplified code if you have further questions.

     

    /Philipp

  13. Philipp - I will post a simple compilable example ASAP.  It may take an hour or so because mod, while simple, is connected to a bunch of other stuff in main.

     

    For your convenience, I have created a simple example based on your code at EDA playground (which uses SystemC 2.3.0).  Just add/correct the relevant parts and try to reproduce the problem.  If the module has just the members you listed, I don't think the problem is related to mod itself.

     

    Adding your line to sc_main had no effect (I added it after the call to sc_start, i.e., immediately before the call to return from sc_main).

     

    If you add the line after the call to sc_start, it should lead to an error as you can't instantiate additional modules after the end of the elaboration phase.  If there is no such error, there may be something else going wrong here (memory corruption?).

     

    Do you keep seeing the segmentation fault, if you skip the sc_start call?

     

    /Philipp

  14. The creator struct and its use looks fine to me.

    What's suspicious is indeed the second call to ~mod() from within ~mod() itself.

    What types of members do you have in mod?  How do you initialize them?  Do you (ab)use smart-pointers?
    What happens, if you add the following line to sc_main?

    delete new mod("tmp", args1, args2);
    

    Can you assemble a minimal but compilable example demonstrating the problem?

    From your description above, it's more or less just the (relevant parts of the) definition of mod that's missing.

     

    @dakupoto: The sc_vector itself will cleanup its allocated elements.  A creator function/class for sc_vector is one of the rare examples, where users must not write their own delete to the new.

     

     

    /Philipp

  15. I believe the assertion occurs before simulation, because stack_protect is called from sc_thread_process::prepare_for_simulation.

     

    Of course, sc_thread_process::prepare_for_simulation is called for dynamic processes as well, see sc_simcontext::create_[c]thread_process. But you should be able to observe the start of the simulation before the assertion fails, in case of a later resource exhaustion being the problem.

     

    I did reduce the number of threads per instance from 4 to 2 to attempt to solve the issue, but it did not help. Instantiating over 6000 still resulted in an assertion violation regardless of 2 or 4 threads.  If it is hitting the max_map_count value I would think that reducing the number of threads would help.  I need to do some more investigating.

     

    You don't provide sufficient information about what kind of module you instantiate 6000-8000 times.  Based on your comments, you seem to have at least 12000 threads in your simulation, which indeed seems to be quite many.  You could try to add a simple (static) counter to the stack_protect call and print out a message for the first failing mprotect call to shed some more light on this issue.  My guess would still be that some OS resources are running low.

     

    /Philipp

  16. I am going to fix this part of code. I think it still better to invalidate certain dmi access inside the list than destroying the whole vector by calling clear().

     

    It depends on your particular scenario, whether there is a significant benefit in maintaining a complex set of DMI allowances.

    If you think it is necessary, I would recommend to

    • implement a dedicated data structure to store the DMI access information, which you can reuse and test separately
    • keep the ranges non-overlapping and sorted by start-address (and probably have two sets for reads and writes in the initiator)
    • use std::lower_bound to efficiently search the sorted vector internally
    • merge adjacent/overlapping entries to keep the number of entries small
    • forward the invalidate_direct_mem_ptr call to update the ranges in the (internal) vector

    /Philipp

  17. First of all, it is recommended to keep the stack protection activated (where available) to avoid arbitrary memory corruption upon stack overflow.  Stack-related memory corruption is very hard to debug...

     

    Assuming, you're running on Linux, then secondly, there are indeed (kernel) resources allocated within the mprotect call.  Quoting the mprotect(2) manpage:

    ERRORS
    ...
           ENOMEM Internal kernel structures could not be allocated.
    
           ENOMEM Addresses in the range [addr, addr+len-1] are invalid for the address space of the  process,  or
                  specify  one  or  more  pages  that are not mapped.  (Before kernel 2.4.19, the error EFAULT was
                  incorrectly produced for these cases.)
    

    Activating the memory protection on some page(s) requires to setup an appropriate memory mapping, of which a limited number can be created by the kernel.  You can try to increase this limit by

    $ sudo bash -c 'echo 131060 > /proc/sys/vm/max_map_count'
    

    (which doubles the default number on my system).

     

    Last but not least, some additional questions:

    • Do you encounter the problem during elaboration or during simulation?
      If it occurs during simulation, you may have "leaking" dynamic processes. If possible, try to reuse dynamic process instances you've created.
    • Which version of SystemC are you using?
      There has been an internal "dynamic process/object leak" in some cases, which has been fixed in SystemC 2.3.0.
    • Can you change some thread processes to method processes?
      SC_METHODs have a significantly lower simulation overhead.  Especially, when you're using thousands of processes, this may be a worthy optimization.

    Hope that helps,
      Philipp

  18. The problem in those two lines is probably that you never clean up your p_dmi vector? 
    Does it help to empty it when invalidating the DMI access in invalidate_direct_mem_ptr?

    p_dmi_enabled = false;
    p_dmi.clear();
    

    Otherwise, you may need to implement a more efficient way to handle multiple active DMI accesses with a custom DMI table wrapped around p_dmi, allowing more efficient address range handling and lookup, e.g. by combining and sorting address ranges and avoiding duplicates.

     

    NB: Obviously, modelling a memory latency in the initiator does not improve the simulation speed of the model.  I probably misunderstood your original question here.

  19. The code is still quite wrong: an array of pointers is not a two-dimensional array and won't work at all.  You need to pass a contiguous memory block as data pointer in the generic payload.

     

    As said in my previous answer, you need to provide a buffer of the target type (i.e. the two dimensional array), not a raw pointer of unsigned char.  Otherwise alignment, offsets and arithmetic will go completely wrong.

     

    I don't really understand, what you intend to do in print_memory, as there are still quite strange constants in use (128, 32, vs. MSIZE1, MSIZE2).  Nevertheless, I tried to address your "casting issue" in the following (fully untested) snippet:

    template <typename DATA_TYPE, unsigned int BUS_WIDTH>
    void traffic_injector<DATA_TYPE,BUS_WIDTH>::print_memory(){
         tlm::tlm_generic_payload trans; // no need to use a pointer, avoid memory leaks!
         trans.set_address(0);
         trans.set_read();
         trans.set_data_length(32); // you only read 32 bytes?!
    
         // don't use a char pointer.  use the "real" type instead
         // again, no need for dynamic allocation with leaking memory
         uint32_t data[MSIZE1][MSIZE2]; // sizes are just a guess
        
         // cast for generic payload data pointer
         trans.set_data_ptr(reinterpret_cast<unsigned char*>(data));
         // don't you want to read the whole memory?
         trans.set_data_length( sizeof(data) ); 
    
         uint32_t count = initiator_socket->transport_dbg( trans );
    
         for(uint32_t j=0;j<MSIZE2;j++){
             for(uint32_t i=0;i<MSIZE1;i++){
                // no cast here, correct pointer arithmetic
                printf("MEM[%d][%d]=%d \n",j,i,data[i][j])));
             }   
         }
    }
    

    Side note: Please educate yourself about the C++ memory model and management.  You leak memory in nearly every function.  Never use new without a matching delete, C++ is not Java or C#.

     

    hth,
      Philipp

×
×
  • Create New...