Jump to content

Philipp A Hartmann

Members
  • Content Count

    533
  • Joined

  • Last visited

  • Days Won

    128

Everything posted by Philipp A Hartmann

  1. Sounds like you didn't look up the suggested parts in the standard. /Philipp
  2. 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
  3. Make sure that you have the "process" function declaration in the body of host_cntrl: class host_cntrl : public sc_module { public: // SC_CTOR(), etc. private: void process(); }; /Philipp
  4. You don't have a member function called 'process' in your 'host_cntrl' class? Hard to tell without actual code. /Philipp
  5. 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
  6. 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
  7. 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. This looks unrelated and is probably caused by accessing unbound ports too early. 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. 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
  8. 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. 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
  9. 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
  10. 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. 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
  11. 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
  12. 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
  13. 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.
  14. 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
  15. I didn't review the full source code. To add a delay to the DMI access, you can add a wait after the memcpy call: if( i->get_write_latency() != sc_core::SC_ZERO_TIME ) wait( length * sizeof(*data) * i->get_write_latency() ); The write latency needs to be filled by the target and/or interconnect modules that fill the tlm_dmi information. As said before, see IEEE 1666-2011, Section 11.2 for details, especially 11.2.5 (ab)-(ad). Generally speaking, you should respect the time annotation received from the target/interconnect in the non-DMI case as well. The corresponding wait(t) call is currently disabled in your code. hth, Philipp
  16. When using DMI, the initiator is responsible for modelling read/write latencies, since no explicit transactions are generated for each access. Unless your processor model adds additional delays for the direct memory accesses internally, it is expected that DMI does not consume simulation time. To approximate the access delays, the target (and the interconnect in-between) can fill the latency fields in the tlm_dmi structure during the get_direct_mem_ptr call, when granting the DMI access to the initiator: class tlm_dmi { public: // ... sc_core::sc_time get_read_latency() const; sc_core::sc_time get_write_latency() const; // ... void set_read_latency(sc_core::sc_time t); void set_write_latency(sc_core::sc_time t); }; For more information, see IEEE 1666-2011, Section 11.2. Greetings from Oldenburg, Philipp
  17. In the print_memory function, you allocate (and never delete, but this is a separate problem) a plain unsigned char array: unsigned char* data = new unsigned char[128]; trans->set_data_ptr(data); Later in that function, you try to use it as a two-dimensional array: printf("MEM[%d][%d]=%d \n",j,i,*(reinterpret_cast<uint32_t*>(&(data[i][j])))); Obviously, this can't work. Apart from the invalid dimensions, the offsets and alignments will also be quite wrong for casting the values to uint32_t, I suppose. Instead, you should use a properly typed array within print_memory (maybe even related to the DATA_TYPE template argument?) and cast it to unsigned char when passing it to the set_data_ptr of the transaction. Some other observations in that function: Why do you allocate the generic payload object with new? (memory leak) Why do you allocate the array with new? (memory leak) Using hard-coded constants (128, 32, ...) seems to be inconsistent with MSIZE1, MSIZE2… I didn't look at the other parts of the code. /Philipp
  18. Side note: If you don't use dynamic processes in your code, just using the aforementioned convenience sockets should no longer require to manually define SC_INCLUDE_DYNAMIC_PROCESS since the release of (Accellera proof-of-concept) SystemC 2.3.1 and its bundled TLM version. /Philipp
  19. You need to keep out "sc_main_main.cpp" (and "sc_main.cpp", providing the main() function) from your DLL building project. Windows DLLs do not support unresolved symbols, unlike ELF shared objects do. You then need to add (a library containing) sc_main(_main).cpp/obj to your application, to provide a main and to properly initialize the kernel via "sc_elab_and_sim". Of course you can adjust the implementation of this function to not call (the unresolved) sc_main function but add another mechanism to enter the user model at this point. hth, Philipp
  20. No, you can also explicitly init() the sub-vectors in a loop, as you did before. A creator function is only strictly needed if you are forced to call a custom constructor for the vector elements, e.g. with additional parameters. In the vector of vector case, this can be the size of the vector. You can pass any C++ entity that can be called with a signature (const char*, size_t) and returns a pointer of the correct vector member type. The sc_bind example is a convenient way to pass additional information to the creator. By binding a member function, you can for example access the members of the module within the creator. In both examples you have quoted after your question, you see the options to pass additional information to the creator. In case 1, it is an explicit constructor argument passed to the my_module_creator function object, in case 2, it's the this pointer, passed to sc_bind. With a C++ lambda, you can use the various "capturing" mechanisms. /Philipp
  21. Yes, if you use an sc_vector in your sub-module //possible alternative: but how do i bind this using sc_assemble_vector sc_vector<sc_in<sc_uint <16> > > in; SC_CTOR(sub_module) :in("in",3) // note the required name prefix, naming objects is good style anyway {} and an sc_vector of sc_vectors for the top-level ports (or a flattened sc_vector and then use the iterator-based binding API), you can use sc_assemble_vector to bind the whole hierarchy in one call (outside of the loops): // vector of ports sc_vector<sc_vector < sc_in<sc_uint<16> > > > in_vec; // ... and in the constructor sc_assemble_vector( m_sub_vec, &sub_module::in).bind( in_vec );If you want it even more neatly, use a "custom creator" to initialize the two-dimensional port vector: // creator function (beware of the hard-coded size 3) static sc_vector<sc_in<sc_uint<16> > >* create_in_vector(const char* nm, size_t ) { return new sc_vector<sc_in<sc_uint<16> > >(nm,3); } // constructor - look, ma', no loops! module( sc_core::sc_module_name, unsigned n_sub ) : m_sub_vec( "sub_modules", n_sub ) // set name prefix, and create sub-modules , in_vec( "in_vec" ) // set name prefix, no init yet { in_vec.init(n_sub, create_in_vector); // use custom creator // push it even further: use a C++11 lambda as a creator // in_vec.init(n_sub // , [](const char* nm, size_t) // lambda function // { return new sc_vector<sc_in<sc_uint<16> > >(nm,3); } ); // do the binding sc_assemble_vector( m_sub_vec, &sub_module::in).bind( in_vec ); } Hope that helps, Philipp
  22. Before trying to answer your question, can you provide some more information? Why don't you use an sc_vector of boolean input ports instead of an array in your submodule? How do you want to wire up the top-level module signals with the submodule signals (indexwise)? Can you provide a stripped-down but compilable code example? (add comments for the missing parts) In general, it is possible to have both an array of sc_vectors as well as an sc_vector of sc_vectors. If you don't want to use a custom "creator function", you just need to take care of the proper initialisation yourself. sc_assemble_vector might not be of much help (depending on the intended topology). You can still do the binding manually in a nested loop over both dimensions, of course. /Philipp
  23. And one should add that generating a DOT file along the way instead of merely printing the hierarchy is not significantly more complex.
  24. Yes, static members are shared among all instances of a class. But, a class template is more like a recipe to build classes. The instances of a class template are all different classes. The static members of "t1" and "t2" can differ, because t1 and t2 are instances of different classes (my_top<17> and my_top<42>). These classes just happen to both have static constants named depth, etc. as they are cooked (instantiated) from the same recipe (template). /Philipp
  25. I don't understand, why using the top module with different values of TOP_DEPTH is a showstopper for declaring the DEPTH_MODULE_xxx as static members of my_top. Integer template arguments have to be known at compile-time in order to instantiate the correct type. Would something like the following be sufficient for your situation? template <int DEPTH=10> SC_MODULE(sub_module_xxx); template <int TOP_DEPTH=10> SC_MODULE(my_top) { static const int depth = TOP_DEPTH; // I usually forward template constants to proper member constants static const int depth_a = depth + 1; // or other math on depth static const int depth_b = depth / 2; // ... sub_module_a<depth_a> sub_a; // no need for pointers? sub_module_b<depth_b> sub_b; SC_CTOR(my_top) : sub_a("sub_a") // initialize sub-modules , sub_b("sub_b") {} }; int sc_main(int, char*[]) { my_top<17> t1("t1"); my_top<42> t2("t2"); sc_assert( t1.depth == 17 && t1.depth_a == 18 ); sc_assert( t2.depth == 42 && t2.depth_b == 21 ); return 0; } Greetings from Oldenburg, Philipp
×
×
  • Create New...