Jump to content

David Black

Members
  • Posts

    690
  • Joined

  • Last visited

  • Days Won

    154

Everything posted by David Black

  1. Usually, we compile the client code to run on a simulated processor, usually known as an ISS (Instruction Set Simulator). This will give you the correct behavior. The ISS will call wait periodically and thus do what you desire. One other possibility that I hesitate to suggest is to run your system code in a separate OS thread (not a SystemC thread) and then interact with it via proper thread-safe semantics (probably using a custom primitive channel utilizing asyc_request_update). I can reasonably expect this will not provide satisfactory results because it will not provide the proper timing relationships. This approach is also fairly complicated and requires a solid understanding of concurrency concepts and how the SystemC simulator works.
  2. In a cooperative multitasking environment (e.g. SystemC), it is impossible to have an infinite loop without yielding. The only yielding method available in SystemC threads is the wait() method; therefore, you have self-defined an impossible problem. SystemC processes (SC_THREAD and SC_METHOD) are NOT the same concept as OS processes or threads. They are constructs of the discrete event driven simulator known as SystemC. Now it is possible in some cases to trick the code, which I have used for some cases. For example, if your FW_main code where to attempt some I/O with a common method, then you could have that method call wait(). This works well when modeling an embedded system using an RTOS and you can modify one of the drivers minimally (i.e. to insert wait()).
  3. Be very careful with terminology here. If you are asking about host simulator OS threads, the answer is pretty much no. SystemC is a discrete event driven simulator using cooperative multitasking (which greatly simplifies coding) and is not thread safe. You might want to look at what is contributing to the slowdown. You should probably use a software profiler. There are two issues that commonly cause problems in SystemC: I/O. More specifically output to the log file. If your simulation has lots of SC_REPORT_INFO or std::cout producing large logs at run-time, then you will definitely want to fix that. Use SC_REPORT_INFO_VERB to reduce I/O and select an appropriate verbosity. Clocks. Fast SystemC models do not use sc_clock. This is easy to do if carefully thought out up front. RTL designers usually have more trouble understanding this and so I typically see RTL designers struggling with the removal of clocks.
  4. I don't know where you got that specification, but it looks suspiciously like a university project. Also, whoever is using the word 'static' is not using the word correctly. Nor would or should that approach ever work. The diagram implies a hierarchy of SystemC modules with a cluster module containing several DME-array modules, which in turn contain DME, DMA and MemType2 modules. These could of course be modeled without the illustrated boundaries, but it would add unnecessary complication. The outermost module (Cluster module) would have one each of an initiator and target TLM-2.0 socket (NOT static). You might choose to have a intervening convenience method to allow the "pointer" design that is requested.
  5. Nothing wrong. Your output will be available after the delta cycle completes. You can view the new value in the next delta cycle. The problem for you conceptually is that you think 'S_val_out = expression' is a blocking statement. In other words, you expect the value to be transferred to the current value of S_val_out at the end of the assignment. Actually what is happening is akin to: S_val_out->write( A_val_in->read() +B_val_in->read() ); External to your sum class object, the S_val_out is bound to a channel sc_signal<T>, where the write() method is implemented. The write method does something like this: template<typename T> class sc_signal : sc_signal_in_if<T>, sc_signal_inout_if<T> { void write( T value ) { next_val = value; request_notify(); } T read() { return curr_val; } void notify() { curr_val = next_val; } }; SystemC will call notify at the end of the delta cycle after all other processes in the current delta cycle have completed their work. You could force code displaying the sum into the next delta cycle with: wait(SC_ZERO_TIME); but that could theoretically affect the other wait depending on how the inputs are being driven and cause you to miss updates.
  6. No problem. Glad you got what you needed. For what it's worth, the return value from system calls is generally 0, 1 or 256. Believe I read somewhere that values above 256 are reserved for OS. 0 means success, and all others mean failure. I generally return 1 to indicate "errors detected while running".
  7. Yes and no. SystemC ports (e.g., sc_port<T>) sit on the boundary of a SystemC module to allow communication with external channels. They point outward from a module towards the channel. SystemC exports point inward towards a channel within the module or within submodules via additional export. sc_in<T> is a partial template specialization of sc_port using an sc_signal_in_if<T>. So the answer to your question depends on where the ports are located vs. the module and channel. A picture would help. What books on SystemC have your read?
  8. sc_fifo<T> is a channel representing hardware FIFO behavior. sc_fifo_in<T> is a specialized port used to access an sc_fifo channel. Almost identical to sc_port<sc_fifo_in_if<T>> Suggestion: Read the freely available SystemC standards document (IEEE-1666-2011) or obtain a book on SystemC. It's all very clear there.
  9. @GUESTWhen you say the size of each FIFO is an input, do you mean to say that during simulation the maximum legal size of the FIFO's is a dynamically changing input? Or is it the case that each FIFO is a different maximum size that is determined at statically at time zero before the simulation gets beyond the elaboration phase? Your answer to this has a critical impact to the response. sc_fifo is a static hardware feature and the nature of hardware is that it may not be changed after fabrication (elaboration is the simulator terminology). If you are looking to model varying software inputs, you may be using the wrong structure. Perhaps you could use a tlm_fifo or you need to use a C++ fifo or a std::queue<T>. All of these are valid modeling ideas for SystemC.
  10. Correct. Ports bind to channels located outside the module containing the port.
  11. I don't think sc_vector supports non-sc_object types (pointers are not sc_object's). Maybe you should describe your use-case first, so we can make some sensible solutions.
  12. I can get non-zero values. <https://www.edaplayground.com/x/Zve> If you had read Doug Smith's paper, you would have found the solution, which I put in the above link. Run multiple times and you get multiple seeds. Note: You need to be aware how random seeds are established in SystemVerilog to get this to work properly. So move that function into a package and call it from whatever processes you desire.
  13. Let me start by observing that you probably don't want to initialize an input port. After all, inputs observe information from outside the module. So I will assume you mean an output port. If need be, you could change to use an sc_inout<T> port, but you might create a nasty race condition. The cleanest and most general approach is to write to the port during the start_of_simulation phase. How? Just create a override method, void sc_start_of_simulation(void), in your module. SC_MODULE( Example ) { sc_out<bool> oport{"oport"}; sc_signal<int> local_sig{"local_sig"}; void sc_start_of_simulation( void ) { oport->write( false ); // initialize an external signal via a port local_sig.write( 42 ); // initialize an internal signal } ... the rest of your module ... }; One other thing, I need to clear up a misconception: SystemC ports do not have a value despite the unfortunate presence of the overloaded operator=. The value that you are thinking comes from the port, actually comes from the channel it is connected to. In the case of sc_in<T> and sc_out<T>, the channels are specifically sc_signal<T>. Also, a channel itself is not data. Channels are vehicles for communication and synchronization. When you write to an sc_signal, you are depositing a value into an internal buffer, the future value buffer. When you read from an sc_signal, you are obtaining the value from another buffer, the current value. How and when the future value gets copied to the current value, is the subject of a deeper idea. For sc_signal channels, there used to be special method, init, but that is not standard. It is also the case that a constructor exists in the Proof-of-Concept implementation with a second constructor argument for initialization; however, this is also not yet standardized. So I would avoid either of these approaches.
  14. Even if you do get $system to return 0, using date to choose a random seed has problems as was discussed in Doulos' Doug Smith's excellent white-paper on Random Stability <https://www.doulos.com/media/1293/snug2013_sv_random_stability_paper.pdf>. You would be much better using the TRNG (Truly Random Number Generator) found on most modern processors, and accessible in most OS's including Linux. Better yet, you can use the random_device from the C++11 <random> library as described here: https://www.cplusplus.com/reference/random/random_device/entropy/. Here's some sample code to illustrate: https://edaplayground.com/x/5AW4 You should be able to easily use this with DPI.
  15. Using the same socket for multiple modules indicates a fundamental conceptual error in how modules, threads and SystemC work. Multiple issues: 1. Sockets are intended to model hardware communication points, but not actual wires. Modules are intended to model silicon hardware blocks. Silicon cannot be assigned (copied or moved within an implementation). Modules are intended to each have their own sockets/ports and are disallowed specifically from sharing. 2. You can have multiple initiator modules communicate with a single target module using a multi socket. If you expect, initiators to talk to other initiators, think again since that is not the concept of initiators. For a given transaction, each module acts as either an initiator or a target. If you need two-way communication (i.e., modules initiating from each side), then you will need both initiator and target sockets on both modules. Suggestion: Draw the hardware you are trying to model and supply a diagram for us to consider.
  16. Use the initializer list of the constructor. Or if you are using a compiler with C++11 support, you can use uniform initialization syntax. Easy.
  17. There are numerous ways you can address this: Make the variable public (breaks encapsulation) and provide the object reference. Provide accessor methods to allow restricted access (best) Make the attribute static and public, but then you cannot have a different per instance. Effectively, a class specific global variable. (dangerous)
  18. Three thoughts might be helpful for you to consider: You could of course use next_trigger() in SC_METHOD: SC_MODULE(HARD_WAY) { sc_in<bool> clock, clock_enabled; SC_CTOR(HARD_WAY) { SC_METHOD(gated_method); sensitive << clock; ... } ... void gated_method(void) { if ( clock_enabled and clock.posedge() ) { // Normal operations } else { // Wait until clock is re-enabled next_trigger( not clock_enabled ); } } The better way is to use sc_process_handle::disable() and enable() #define SC_INCLUDE_DYNAMIC_PROCESSES #include <systemc> #include <vector> using namespace sc_core; std::vector<sc_process_handle> gated; //< collect processes needing gating SC_MODULE(EASY_WAY) { sc_in<bool> clock; SC_CTOR(EASY_WAY) { SC_METHOD(gated_method); sensitive << clock; gated.push_back(sc_get_current_process_handle()); ... } void gated_method(void) { // Normal operations } ... }; // Process controlling gating void control thread(void) { ... if ( turn_off_clock ) { for( auto& process : gated ) process.disable(); } if ( turn_on_clock ) { for( auto& process : gated ) process.enable(); } ... } Above approach works on all static SystemC process types. Dynamic processes might escape. A more comprehensive and easier approach could be done if your gated processes are all submodules of a containing module. In that case, you skip the registration issue, because you can simply do a hierarchical search to collect the list of processes that need to be disabled or enabled at the time of power down/up. This approach will also capture dynamic processes.
  19. @omaima RTFM please. It's all in the README and related files. Better yet, signup and take a class from somebody.
  20. If something is not mentioned in the standard, then you should assume it's an internal implementation thing and not to be used by the end-user. Use the syntax of the standard and don't use the syntax of the implementation as your guide. The bug is likely that somebody provided an extra parameter at all.
  21. Or... Use pre-randomize to establish the size and create the array, then you can constrain element creation normally. Determining the size is usually less complex than constraining the contents, so this approach may be more flexible.
  22. Have you tried using CMake installation? That usually works the easiest for me. Of course you need to install cmake (https://cmake.org/download/) and then there's a separate INSTALL guide under the SystemC cmake subdirectory.
  23. Since sc_clock is really just an ordinary SystemC citizen, there is no way to distinguish it per se. Newer versions of SystemC (2.3.3 ff) have sc_event::triggered(). So you could check clock->default_event().triggered(). Don't add a clock to your design. Simulation will be faster. If you need to wait 500 clocks use: wait( 500 * PERIOD ); You might consider looking at my design of no_clock here> https://github.com/dcblack/no_clock
  24. This appears to be a problem for Mentor Graphics since UVM-1.2 compiles fine with their other tools. It may be a limitation of ModelSim. As stated earlier, if you want to use UVM for learning/experimentation, then https://www.edaplayground.com is available. On the other hand, if you are wanting to do a real project, then you must purchase a full blown simulator from a commercial vendor.
  25. @Eyck is correct. It would be a major rewrite of SystemC to allow this. If you are trying to launch multiple simulations (sequentially) perhaps with different parameters, you need to do that from a script. If you are super insistent you have to do it under C++, you could try the following: // Compile your main SystemC as run.exe and place it in the same directory as this program int main(void) { int errors = 0; errors |= system("./run.exe -option 1"); errors |= system("./run.exe -option 2"); return errors; } Or just use your favorite script language (bash, perl, zsh, csh, python) to do the equivalent. You can store results in files and read configuration data from files. It's just C++. If you want to rewrite the main.cpp from the library, feel free to do so, but you still won't be able to reset SystemC's internal data structures without invoke a completely new process.
×
×
  • Create New...