Jump to content


Popular Content

Showing content with the highest reputation since 07/16/2017 in all areas

  1. 3 points
    Because your "analyzer" instance is a local variable in the before_end_of_elaboration function, which gets destructed immediately, when the function returns. So there is no analyzer left to call the callback on later (same holds for the local signal sig2, btw.). You would need to allocate the module dynamically instead. You cannot alter/modify/redefine any existing port binding at any time. You can only add new bindings, including during before_end_of_elaboration. Hope that helps, Philipp
  2. 2 points
    In general, SystemC models should avoid using clocks altogether. This is good for many reasons assuming your goal is high speed behavioral models. SystemC is often used for implementing functionally accurate virtual platforms that allow software to be designed well ahead of hardware delivery. Thus appropriate use of next_trigger() is actually a great idea. There is no way to distinguish between static and dynamic triggering at the point of invocation. Clock is synthesizable and if that particular mode of design is your goal, then sc_clock is appropriate. There are no features of SystemC itself that will tell you if the code itself is synthesizable. The answer to that is highly tool dependent. I know synthesis tools that require no clock at all, and others that insist a clock be specified. Always keep in mind: SystemC is simply C++ syntax used with a library and a methodology to model hardware and software. C++ has no concept of synthesizability. You have to go beyond GCC/LLVM to find out if your code is synthesizable with a given synthesis tool.
  3. 2 points
    This question cannot be answered with respect to the SystemC standard as the issue is heavily implementation dependent. I am aware of implementations where SC_THREAD is faster than SC_METHOD and visa versa. It is also not a good basis for evaluating SystemC itself since the issue of simulation performance almost always comes down to how SystemC was used and how the modeler wrote their SystemC model. I do know an awful lot of folks use SystemC inappropriately (e.g. using it for modeling RTL, where VHDL or SystemVerilog are much better suited). IEEE 1666-2011 calls out the desired behavior, and not the implementation. Note: I did a presentation on SystemC myths many years ago at NASCUG that included the myth about whether or not one should favor SC_METHOD over SC_THREAD for performance reasons. It is quite simply a poor way of making a decision when attempting to obtain performance.
  4. 2 points

    Reading a binary File

    Yes, you can use C's fread() function for this purpose. However, you should not use malloc()/free() to handle allocation/deallocation of your buffers. Instead, use C++'s new/delete operators or even better a suitable standard container such as std::array<T, N> or std::vector<T>. C++'s <iostream> library also offers you the possibility to read/write binary data from/to files. SystemC is a C++ library. Therefore, I suggest that you get familiar with C++ first. Confer, e.g., to: https://isocpp.org/get-started http://www.cplusplus.com/reference/iolibrary/ https://stackoverflow.com/questions/8798127/binary-input-output-in-c
  5. 2 points
    This question in mostly about how the linker works on your platform, and not really specific to SystemC. Let me try to give a short summary: Yes, the "main" symbol is needed by the final application For every needed symbol, the linker looks in your object files first If the symbol is present there, the linker picks it up If not, the linker looks in the libraries given by the user (order/lookup is platform-specific) Repeat this for all required symbols (including "sc_main") So, if you define your own "main" in your application, SystemC's "main" will not be picked. This is actually a feature, as you can call "sc_elab_and_sim" manually from your "main" as well, if you want. Hope that helps, Philipp
  6. 2 points
    Hi Jarodw, Thanks for your report. I can confirm and reproduce the issue in SystemC 2.3.2. It looks indeed like a regression compared to SystemC 2.3.0/1 that has been introduced by the fix for optionally unbound sockets, see: It seems, the SystemC regression tests didn't cover the hierarchical binding for the multi sockets, so it wasn't caught before the release. Your example can be fixed by changing line 228 in src/tlm_utils/multi_passthrough_target_socket.h: if (unbound && !m_hierarch_bind) return; // ^-- add check for hierarchical binding here Hope that helps, Philipp
  7. 2 points
    Philipp A Hartmann

    makefile SystemC

    You can check out the example Makefiles in the installation (examples/build-unix/Makefile.{config,rules} and e.g. examples/sysc/simple_bus/Makefile) as a starting point. The files in examples/build-unix are reasonably generic, and you may "just" need to adjust the settings in Makefile.config. In the project's Makefile itself, you then set the PROJECT variable and your SRCS (to point to your source files). Admittedly, documentation could be better (as usual), but you can ask here, if you have further questions. The CMake support included in SystemC 2.3.2 is still experimental and is mostly targeted for early adopters with CMake knowledge. Greetings from Duisburg, Philipp
  8. 2 points

    Clock to Q Propagation Delay

    Hello, In SystemC you can use SC_THREAD's to model delays by using wait statements but you will incur performance penalty. Instead you can use event's and event queues to model delays using in SystemC as mentioned here: http://workspace.accellera.org/Discussion_Forums/helpforum/archive/msg/msg?list_name=help_forum&monthdir=200803&msg=msg00061.html You can replace the SC_THREAD example given in the above mentioned link with SC_METHOD removing the infinite while loop. Here's the modified example listed from the above mentioned link: template<typename T> class delay_transport : public sc_module { public: sc_in<T> in; sc_out<T> out; SC_HAS_PROCESS(delay_transport); delay_transport(sc_module_name name_, sc_time tdelay_) : sc_module(name_), tdelay(tdelay_), in("in"), out("out") { SC_METHOD(mi); sensitive << in.default_event(); SC_METHOD(mo); sensitive << eq; } sc_time tdelay; void mi() { val = in.read(); vq.push(val); eq.notify(tdelay); } void mo() { val = vq.front(); out.write(val); vq.pop(); } sc_event_queue eq; std::queue<T> vq; T val; }; Regards, Ameya Vikram Singh
  9. 2 points
    Yes, but you need to write the constructors yourself (don't use the SC_CTOR macro). Something like #include "systemc.h" SC_MODULE(mod) { int i; mod(sc_module_name nm) : sc_module(nm) { // ... } mod(sc_module_name nm, int i_) : sc_module(nm), i(i_) { // ... } }; If you use SC_THREAD or SC_METHOD you must also include the SC_HAS_PROCESS macro. Try looking up SC_HAS_PROCESS in 1666-2011 and you should find an example near there, regards Alan
  10. 2 points
    Manikanta's solution assumes temp is public. If not public, you can take the opposite approach and simply call sc_trace from within the module itself. You could even do it conditionally based on run-time command-line arguments: sc_core::sc_trace_file trace_file = 0; //< initialize to indicate not open top::before_end_of_elaboration() { for (int i=1; i<sc_argc(); ++i) { if ( trace_file == 0 && std::string(sc_core::sc_argv()[i]) == "-trace" ) trace_file = sc_core::sc_create_vcd_trace_file("your.vcd"); }//endfor } top::end_of_simulation() { if ( trace_file != 0 ) sc_core::sc_close_trace_file(trace_file); } ... extern sc_core::sc_trace_file trace_file; void dut::end_of_elaboration() { if (trace_file != 0) { sc_core::sc_trace(trace_file, temp,"temp"); } } Of course I am assuming fp is made public as shown, and that you have opened it before end of elaboration:
  11. 2 points

    Socket binding to module itself

    An other way to understand this is to look at SystemC/TLM as pure C++ code and see what is going on.. Let us assume that you have two classes, "Initiator" and "Target", that need to communicate with each other. Target implements a function called "transport" to be called by Initiator, and Initiator implements a function called "response" - that is called by target. For the sake of the explanation here, the payload itself is not important, which we will assume is plain "int" in both directions. You would normally do this as following: // Interface classes: class initiator_if { public: void response(int i) = 0; }; class target_if { public: void transport(int i) = 0; }; class Initiator : public initiator_if { public: // Implement the interface void response(int i) { cout << "Got: " << i << " from target" << endl; } void bind(target_if &_if) { // Store the pointer locally m_target = &_if; } }; class Target : public target_if { public: // Implement the interface void transport(int i) { cout << "Got: " << i << " from initiator " << endl; } void bind(initiator_if &_if) { // Store the pointer locally m_initiator = &_if; } }; Next we instantiate the objects and "bind" them: Initiator initiator; Target target; initiator.bind(target); target.bind(initiator); I hope you are seeing where we are going with this. What has been done above is a crude equivalent of sc_port binding. There is one problem however with the approach above. What if the class "Target" doesn't implement the target_if directly? Like so: class TargetGrandChild : public target_if { public: void transport(int i) { // Implement the interface.. cout << "Got " << i << " from initiator (in grand child)" << std::endl; } }; class TargetChild { public: TargetGrandChild gch; /* Other stuff.. */ }; class Target { public: TargetChild ch; /* Other stuff.. */ }; One way to deal with this is to change the way bind function is called: initiator.bind(target.ch.gch); This is ugly. Firstly, it makes the client of bind function dependent on an internal design aspect of the "Target" class. For example, if the Target class changes tomorrow (to let the TargetChild implement the "target_if" directly), the bind function call needs to change. Also, to allow the client to call the bind function as above, the elements "ch" and "gch" must be made public, which may not be necessarily a good thing. A way out is to have an additional indirection. Let us call this as simple_export (a very simplified version of sc_export): class simple_export : public target_if { public: void transport(int i) { // One level of indirection p_real_target->transport(i); } void bind(target_if &_if) { p_real_target = &_if; } private: target_if *p_real_target; }; The new version of the Target class now looks like the following: class TargetGrandChild : public target_if { public: void transport(int i) { // Implement the interface.. cout << "Got " << i << " from initiator (in grand child)" << std::endl; } }; class TargetChild { public: TargetGrandChild gch; /* Other stuff.. */ }; class Target { public: simple_export port; private: // private is ok TargetChild ch; /* Other stuff.. */ Target() { // Tell "export" where the real implementation is port.bind(ch.gch); } }; The initiator will be "bound" to the target like so: initiator.bind(target.port); So for the simple_export to work, you need two binds: First is where the initiator is bound to the simple_export instance Second is when the "real" implementation is bound to the simple_export instance The simple_export class acts like a bridge. It forward the calls from the initiator to the "real" implementation. In case the "Target" itself implements the interface, the bind would look like: class Target : public target_if { public: simple_export port; private: // private is ok TargetChild ch; /* Other stuff.. */ Target() { // Tell "export" where the real implementation is port.bind(*this); } }; I hope this explains the line you pointed out in the code. The TLM socket has both a port and an export. Please note that the code snips above does not correspond to how OSCI simulator actually implements sc_port/sc_export!
  12. 1 point

    Errors in code

    From a quick glance into your source files, I see: Your headers are missing #include guards. You don't include SPPS.h in your header SPPS48.h, but your members M1, M2, and M3 are of type SPPS, which you define in SPPS.h I recommend that you don't use the header <systemc.h>, as it seriously pollutes your public namespace. Use header <systemc> instead and import only the symbols in your current namespace, which you actually use. Your constructor allocates manually memory for the members M1, M2, and M3 using "new", but lacks a destructor, which would release the objects using "delete". Anyway, this is not considered "Modern C++". Instead of raw pointers to objects of type SPPS, use a smart pointer. In your case, std::unique_ptr is probably the appropriate choice. All members of your SC_MODULE are exposed to public. This may be good for debugging, but it is better to only expose those members, which constitute the public interface of your module (i.e., at least the input/output ports, constructor, and destructor). Your SC_METHODs and SC_THREADs don't need to be public. Your approach to generate a clock signal in sc_main() is tedious the most. A clk signal of type sc_core::sc_clock is a more comfortable solution. To generate more comfortably complex stimuli, I recommend that you implement them in an own stimuli module. Therein, you can register an SC_THREAD, which performs the stimuli generation and which can easily wait for delays or event before proceeding to the next stimulus. In the same way a monitor for your output signal can be implemented. I repeat my recommendation to learn first the basics of modern C++ and to read a good book on SystemC to get more efficient in your modelling attempts!
  13. 1 point
    Roman Popov

    port binding

  14. 1 point
    I can also add a quote from the Verilog Standard IEEE 1364-2005, $timescale, describing the grammar rules for the timescale support in VCD: So even here, only powers of 10 are allowed.
  15. 1 point
    Roman Popov

    Bug at file sc_trace_file_base.cpp

    Thanks a lot for reporting! I can confirm that 2.3.2 does not supports v that it is not a multiple of 10. I agree that set_time_unit API is bad (error-prone), and should be changed. Good news that you've received a runtime error early and did not spent lots of time . Do you need support for fractional timeunits? Or just more clear API? I've also checked 2.3.1. It does not works properly with 0.5 either: int sc_main (int argc, char **argv) { sc_trace_file* tf; tf = sc_create_vcd_trace_file("traces"); sc_signal<int> isig{"isig",0}; tf->set_time_unit(0.5, SC_NS); sc_trace(tf, isig, "isig" ); sc_start(0.5, SC_NS); isig = 1; sc_start(2.5, SC_NS); isig = 2; sc_start(3.5, SC_NS); isig = 4; sc_start(3.5, SC_NS); sc_close_vcd_trace_file(tf); return 0; } VCD is incorrect: $date Dec 05, 2017 11:50:52 $end $version SystemC 2.3.1-Accellera --- Dec 5 2017 11:40:15 $end $scope module SystemC $end $var wire 32 aaaaa isig [31:0] $end $upscope $end $enddefinitions $end $comment All initial values are dumped below at time 0 sec = 0 timescale units. $end $dumpvars b0 aaaaa $end #1 b1 aaaaa #6 b10 aaaaa #13 b100 aaaaa So 2.3.2 is better. But not perfect :(
  16. 1 point

    Elaboration time sized array

    Hello Roman, instead of developing your own class, have you considered to use std::unique_ptr<T[]> (C++'11) and std::make_unique<T[]> to allocate your array of a fixed size during elaboration? For examples see, e.g.: http://en.cppreference.com/w/cpp/memory/unique_ptr http://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique Regards, Torsten
  17. 1 point
    If you use SC_THREAD that means that you are using sc_event under the hood. Because every SC_THREAD in SystemC has event that activates the process. You can for example spawn a SC_THREAD process to do delayed assignment like this: #include <systemc.h> struct spawned_assignment_demo : sc_module { SC_CTOR(spawned_assignment_demo) { SC_THREAD(test_thread); } sc_signal<int, SC_MANY_WRITERS> out{"out", 0}; void print_out_value() { cout << " out value = " << out.read() << " at " << sc_time_stamp() << "\n"; } void test_thread() { print_out_value(); sc_spawn([&]() { wait(10, SC_NS); out = 42; }); wait(5, SC_NS); print_out_value(); sc_spawn([&]() { wait(10, SC_NS); out = 124; }); wait(6, SC_NS); print_out_value(); wait(6, SC_NS); print_out_value(); } }; int sc_main (int argc, char**argv) { spawned_assignment_demo demo{"demo"}; sc_start(); sc_stop(); } Output will be as expected: out value = 0 at 0 s out value = 0 at 5 ns out value = 42 at 11 ns out value = 124 at 17 ns But when you call wait(10,SC_NS) you create timed event notification. You can use debugger to step into wait() to see what happens there.
  18. 1 point

    Delta Cycle and concurrency

    Hi. Maybe you should have a look at SystemC AMS. It offers the TDF (timed data flow) model of computation. It follows the data flow concept, i.e. you have a cluster of blocks; the solver defines an order of evaluation of each block; and in every time step, the blocks (or modules) are evaluated in that order. The output of one block is immediately visible at the input of the following block. Greetings Ralph
  19. 1 point
    Starting with SystemC 2.3.2, the MSVC project files shipped with the package use the DLL-based runtime library. Therefore it is not necessary (instead rather harmful) to select the statically linked runtime library in your application. Secondly, you should not set the SC_SIGNAL_WRITE_CHECK environment variable to DISABLE (unrelated to your current issue, but suggested in the video above). More instructions on using MSVC with SystemC can be found in the INSTALL file shipped with the proof-of-concept simulator. Hope that helps, Philipp
  20. 1 point

    Socket binding to module itself

    Hello, I am new in the SystemC-TLM world. I am reading the LRM and looking at an example (chapter 13, systemc LRM, page 462). In the module constructor it is written ... init_socket.bind(*this); // Initiator socket bound to initiator itself ... The rest of the code is of no use for the sake of the question. I don't understand why the socket must be bound to the module itself. The example continues and the socket is bound to a target socket, but I don't get this one... Thank you in advance. Leo
  21. 1 point

    TLM payload extension declaration

    Dear all, I am new to payload extensions and I would appreciate a feedback on whether I am doing things right.. I need to declare a simple payload extension, including two additional fields: a reset value a 16 bit bit vector representing the value of a register In the header, I simply declare the clone/copy from functions, plus my additional fields: class reg_extension : public tlm::tlm_extension<reg_extension>{ public: reg_extension(); tlm::tlm_extension_base* clone() const ; void copy_from(tlm::tlm_extension_base const &); bool reset; sc_bv<16> value; }; And then I implemented the functions, by taking care of the additional reset and value fields: reg_extension::reg_extension(){ reset = false; value = sc_bv<16>(0); } tlm::tlm_extension_base * reg_extension::clone() const{ cout<<"Executing clone!"<<endl; reg_extension * ext = new reg_extension(); ext->reset = this->reset; ext->value = this->value; return ext; } void reg_extension::copy_from(tlm::tlm_extension_base const & ext){ reset = static_cast<reg_extension const &>(ext).reset; value = static_cast<reg_extension const &>(ext).value; } Is this enough for the extension to work? Best regards, S.
  22. 1 point
    This because you need to understand the macro `uvm_oject_utils() See http://go.mentor.com/mcem, then look at the Reference for uvm_object_registry.
  23. 1 point

    Randomization in an initial block

    This is the correct functionality. There is a random number generator (RNG) for every module instance in your design, and it is seeded with a RNG from the module instance it starts from. All all modules instances start out with identical seeds. Every thread that starts inside a module instance grabs a new RNG. Threads in parallel blocks get seeded in declaration order, not in the indeterminate order they might actually start. Objects that get constructed get seeded with an RNG from the thread calling the constructor. This random stability model has a few problems that the UNM attempts to correct by using a path name as an initial seed. You just need to make sure your path names are unique enough to generate distinctive seeds. A good paper to read on this topic is: Random Stability, Don't leave it to chance.
  24. 1 point
    I believe 'force' is intended for net types (e.g. wire) and uses the SystemVerilog 'force' statement; whereas, 'deposit' is intended for variables (i.e. var or reg types). Lookup the 'force' and 'release' statements in the SystemVerilog standard for more information.
  25. 1 point
    The "sc_export" part of each TLM-2.0 socket needs to be bound to an interface (tlm_bw_transport_if for an initiator, tlm_fw_transport_if for a target socket) in order to provide the implementation of the communication link. As you can see in the referenced example, the Initiator class inherits and implements the backwards interface: struct Initiator: sc_module, tlm::tlm_bw_transport_if<> // Initiator implements the bw interface As a result it can act as the "channel" to provide the behaviour for the sc_export part of the initiator socket. This pattern is a quite common idiom in the TLM-2.0 world, at least if you don't use the convenience sockets. So to answer your question: It's not the "module part" that is bound to the socket. The Initiator is-a backwards interface as well, and this "interface part" is bound. Greetings from Oldenburg, Philipp