Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation since 09/23/2020 in Posts

  1. Why not use constructor prameters? Another option would be cci_params. Via the broker they can be given a value before they are created. So you can use them in contructor bodies....
    3 points
  2. As @Eyck suggested, constructor parameters should fit best your needs. You can even give them default values if it is sensible. If the number of parameters grows, grouping them in a struct may become handy. Its members can be default-initialised and you can override them with assignments before passing the whole struct to the module constructor. Personally, I like to first check for consistency and legal range for these parameters in the constructor / member function to which I pass this struct, e.g., by using assertions before actually using them for describing any behaviour/internal structure.
    2 points
  3. Managed to run SystemC on new Apple M1 silicon, following are the steps 1. modify configure file, add the following code highlighted in red # check CPU architecture case ${target_cpu} in #( x86_64|amd64) : TARGET_ARCH="${TARGET_ARCH}64" CPU_ARCH="x86_64" QT_ARCH="x86_64" ;; #( x*86|i*86) : CPU_ARCH="i386" QT_ARCH="iX86" ;; #( powerpc64) : TARGET_ARCH="${TARGET_ARCH}ppc64" CPU_ARCH="ppc64" QT_ARCH="pthreads" ;; #( powerpc) : TARGET_ARCH="${TARGET_ARCH}ppc" CPU_ARCH="ppc" QT_ARCH="powerpc-apple-macosx" ;; #( arm) : TARGET_ARCH="${TARGET_ARCH}arm" CPU_ARCH="arm64" QT_ARCH="pthreads" ;; #( *) : as_fn_error $? "\"sorry...architecture not supported\"" "$LINENO" 5 ;; 2. install g++ using homebrew brew install gcc 3. setting CXX and point to the homebrew g++-11 in step 2, run configure export CXX=g++-11 ./configure 4. make all 5. make check I would like to encourage others to share their experience of porting systemC to this new mac silicon.
    2 points
  4. Thanks @William Lock, for sharing your experience of building SystemC on macOS for the Apple M1 architecture. I opened an issue on the LWG’s internal tracker to update our build scripts so that it will work out of the box in the future.
    2 points
  5. Matthias Jung

    C++20 Co-routines

    For my SystemC-Lecture, I wrote a simple DES simulator to reduce to the minimal mechanisms that are required to understand the DES concept. (https://github.com/myzinsky/des/tree/main/sw). For that I used C++20 co-routines for the 'processes'. Therefore, I was wondering if somebody has considered these co-routines also as co-routines for SystemC, instead of qt, pthreads or fibers?
    2 points
  6. Actually the usual bus protocols allow to send larger number of requests and the interconnect is allowed to answer them 'out of order' (e.g. AMBA AXI or CHI). But you are free to define you onw protocol and its own rules. The LRM states exactly how to do this. One example can be found at https://github.com/Arteris-IP/tlm2-interfaces which defines the extensions and phases for the AXI/ACE and the CHI protocol.
    2 points
  7. Hello @berry_runner, Regarding a dedicated training look here: https://www.doulos.com/training/ But as a starter in this, I would recommend getting to know following in no particular order: C++11/14/17: Useful for writing concise and clean code. SystemC from Ground Up 2nd Edition by @David Black. https://github.com/dcblack/SCFTGU_BOOK/ Look into the examples directory in SystemC sources. https://github.com/accellera-official/systemc/tree/master/examples Look into publicly released projects on Github: https://github.com/topics/systemc Follow similar discussions in this forums: If you still have queries you can post in the forum for community support. Hope this helps. Regards, Ameya Vikram Singh
    2 points
  8. Port requires a pointer towards the object containing implementations of methods specified in the interface. Export provides the very pointer that port needs. Port goes from caller towards callee. Export goes from callee towards caller. Pseudo-graphically: // +----------------------------------------------------------------------------------+ // |struct Top : sc_module { | // | | // | initiator.p1.bind( target.x1 ); | // | | // | Initiator initiator{"orgin"}; Target target{"target"}; | // | +------------------------------------+ +--------------------------------------+ | // | |struct Initiator : sc_module { | |struct Target : sc_module { | | // | | | | | | // | | sc_port<IF> p1{"p1"}; | | sc_export<IF> x1{"x1"}; | | // | | caller.p0.bind( p1 ); | | x1.bind( callee.x0 ); | | // | | | | | | // | | Caller caller{"caller"}; | | Callee callee{"callee"}; | | // | | +----------------------------+ | | +------------------------------+ | | // | | |struct Caller : sc_module { | | | |struct Callee : sc_module, IF | | | // | | | | | | | | | | // | | | sc_port<IF> p0{"p0"}; | | | | sc_export<IF> x0{"x0"}; | | | // | | | SC_THREAD(thread1); | | | | Data m_data; | | | // | | | | | | | x0.bind(*this); | | | // | | | | | | | | | | // | | | .------------------. | | | | .----------------------. | | | // | | | | void thread1() | | | | | | void xfer( data& d ) | | | | // | | | | { | | | | | | { | | | | // | | | | p0->xfer( v ); | [p0]->[p1]->[x1]->[x0] | // Save/load d | | | | // | | | | } | | | | | | auto t = d; | | | | // | | | | | | | | | | d = m_data; | | | | // | | | | | | | | | | // Transform t | | | | // | | | | | | | | | | m_data = t; | | | | // | | | | | | | | | | } | | | | // | | | '------------------' | | | | '----------------------' | | | // | | | | | | | | | | // | | |}; | | | | | | | // | | +----------------------------+ | | +------------------------------+ | | // | | | | | | // | |}; | |}; | | // | +------------------------------------+ +--------------------------------------+ | // | | // |}; | // +----------------------------------------------------------------------------------+
    2 points
  9. It is doubtful to support since it would devote too many resources (specification, design, implementation, security, verification, training) from too many companies (SYNOPSYS, Cadence, Siemens EDA, Aldec) for something of little real benefit (commercial and practical). Another language interface would fragment support for an already complex language. No thank you. You can always use SWIG if you really feel the need.
    1 point
  10. Hello @Soumyajeet, As per the sources: https://github.com/accellera-official/systemc/blob/604182509559ae42c34e878f508bae7c18abbbd6/INSTALL.md#L602 It mentions that the SC_CPLUSPLUS would be set to the latest value configured at the compiler level/command line flag. I am using C++20 in my SystemC environment without any issues. Hope it helps. Regards, Ameya Vikram Singh
    1 point
  11. I've opened this as an issue at on mantishub: 0007404: uvm_reg_hw_reset_seq exclusions appear incorrect - Accellera Mantis (mantishub.io) Thanks!
    1 point
  12. Your observations are correct, but it really is not a problem. Even in Verilog you cannot do differently: // Verilog/SystemVerilog module Design( input CLK, AV, RD ); always @(posedge CLK) if ( AV == 0 && RD == 1 ) begin WriteDataOut(...); end endmodule So in SystemC: #include <systemc> using namespace sc_core; //< Simplifying bad practice SC_MODULE(Design) { sc_in<bool> CLK, AV, RD SC_CTOR(Design) { SC_METHOD(main_method); sensitive << CLK.pos(); } void main_method() { if( not AV->read() && RD->read() ) { WriteDataOut(...); } } }; Event driven simulators trigger on events, not values. In case you get distracted, here is a solution that will not work despite appearances: #include <systemc> using namespace sc_core; //< Simplifying bad practice SC_MODULE(Design) { sc_in<bool> CLK, AV, RD SC_CTOR(Design) { SC_METHOD(main_method); } void main_method() { next_trigger( CLK->posedge_event() & AV->posedge_event() & RD->negedge_event()); //< not what you might think if( not AV->read() && RD->read() ) { WriteDataOut(...); } } }; The & in the next trigger means that invocation will occur when all three events have happened; however, there is no requirement on when they occur. In other words, they won't be lined up correctly.
    1 point
  13. Hello @Shashank V M, That's why you need to use a non-blocking process SC_METHOD to model such behavior. You can find relevant discussion here: Hope it helps. Regards, Ameya Vikram Singh
    1 point
  14. If you want to set the initial value of the signal to which the port int_o will be bound during elaboration, you can use the member function initialize() (cf. to clause 6.10.4 of IEEE Std 1666-2011).
    1 point
  15. Show your code please. Better: get a free account on EDAplayground.com and share your code from there.
    1 point
  16. It is not correct to bind a port to another port directly except in the case of a hierarchical connection. Furthermore, there is no such thing as an input port or an output port in SystemC. Ports are simply sophisticated pointers to channel objects that provide methods for exchanging information. Some methods are directional in nature by g to heir behavior. For instance, sc_signal<int>::write(value) deposits it’s contents into memory managed by the sc_signal<int> channel.
    1 point
  17. Hello @Saikat, Regarding your questions. Since SystemC is written in C++, g++ should be the default. Regarding compiler warning the ones mentioned in your post: Seems a good enough list for now. I would prefer you going through your compiler manual to figure which ones you might need. But, as my personal preference I usually prefer to build my code with various compilers and on various platforms to get the best possible platforms compatible code. It is very easy the write a code which might end up being platform/compiler dependent. Better to stick with standard C++ language compliance to get the most out of your code. Regards, Ameya Vikram Singh
    1 point
  18. I concur with Eyck's comments. A few more thoughts: SystemC-processes are very different from OS processes. SystemC itself runs inside a single OS-thread. SystemC uses cooperative multitasking to simulate SystemC processes, which come in three flavors: SC_THREAD, SC_METHOD, and SC_CTHREAD (for synthesis). This is common among discrete event-driven simulators (e.g., Verilog, SystemVerilog, and VHDL use the same idea) Cooperative multitasking simplifies the coding a lot to make it easier for designers using these simulators. When documenting, I find it useful to keep these distinctions clear. To re-iterate: OS-processes and OS-threads are preemptive in nature. OS-threads live within the context of OS-processes. The primary distinction being that OS-threads share common resources (primarily memory). SystemC-processes live within a single OS-thread. SystemC-processes are not preemptive in nature, and must yield in order to allow other processes to run (i.e., cooperate to allow the simulation to proceed). The distinction between SystemC-processes is the manner in which they yield to each other: SC_THREAD-processes and SC_CTHREAD-processes yield by calling sc_core::wait(). SC_METHOD-processes yield by returning. When communicating between SystemC and an external OS-thread, SystemC events may only be invoked from within the context of the SystemC OS-thread. To inject an event, you may devise a primitive channel using async_request_update() to inject events via the update() method. C++11 provides an OS-agnostic library to create OS-threads, which is very handy. Keep in mind that data transfers between two processes must be carefully guarded using a proper mutex (available in C++11). I suggest you use a guarded mutex.
    1 point
  19. SystemC is a single-thread simulator and moreover not thread-safe due to various reasons. The problem you are facing is that you modify datastructures in the SystemC kernel (by calling notify() ) asyncronously since you are running it in another (OS-)thread. This might work in some case but in most cases it will not. To cut a long story short you cannot use sc_event to syncronize os-threads. But there are means to handle this case namely async_request_update(). To see an example you might check out https://stackoverflow.com/questions/49814756/async-request-update-example-in-systemc esp. the implementation of class ThreadSafeEvent. One remark: I strongly suggest to use C++11 and there std::thread since it makes your code more readable and abstracts from the underlying API. E.g. PThread is not a native Windows thread implementation rather belongs to some POSIX layer which might introduce additional issues.
    1 point
  20. Be aware that SystemC kernel is not threadsafe with exception of async_request_update(). So you must code accordingly.
    1 point
  21. uvm_config_db is simply a facade pattern on top of the uvm_resource_db. As mentioned above, most recommend avoiding direct use of the resource db because the config db adds more consistency to its use.
    1 point
  22. 1. uvm_resource_db is a datbase which is used as basis for uvm_config_db. uvm_config_db is adding more flexibility to uvm_resource_db. 2. You should never use uvm_resource_db 3. Is obsolete because of 2.
    1 point
  23. You’re only allowed to call sc_trace one time for each variable and after that tracing is automatic. So you need to move the sc_trace calls out into the constructor or into end_of_elaboration or somewhere else before simulation starts. You also need to move your local variables in to the class as members.
    1 point
  24. No, you cannot run the SystemC simulator kernel as a Linux kernel module for sevberal reasons: SystemC requires quite some libraries (libc, libqt, ...) that are not available in kernel space You would taint the kernel and open up a security hole large as a gate. You would alos risk the system integrity. SystemC is simply not meant for such things. A proper design would make a distinction between (as little as possibel) code to run in kernel space providing interfaces (devices or shared memory) to interact with and a userspace application which could be the SystemC simulation e.g. running as a daemon. Even linux kernel hackers move everything into this direction... Yes, the simulation is a simple userspace process being constraint by the OS permissions. So it can use all resources a process is allowed. It can open socket connections and ports and whatever it needs. In the past I wrote some interface which allowed the SystemC simulation running on a Linux system to talk to another simulator running on a Windows host using network sockets (it also worked with UNIX domain sockets). And actually we are implementing a SystemC simulation talking to an FPGA on an accelerator card via device files. Unfortunately I'm not aware of freely available examples to do so. But if you have some C/C++ code to deal with the netlink sockets you can just embed this code into the simulator e.g. as part of a sc_module and tie it to the simulation phases (open the socket during start_of_simulation(), closing them during end_of_simulation()).
    1 point
  25. Yes, it is possible. Since SystemC is basically a C++ class library you can you whatever C/C++ allows for.
    1 point
  26. You'll have to create internal (i.e., private) signals for each member of the bundled class, which you need to connect to sub-blocks. Then, you have to register a SC_METHOD or SC_THREAD, which is sensitive to changes of the bundled input. The method/thread can then assign the correct new values to the internal signals based on the changed bundled input.
    1 point
  27. On a side note, you might also consider moving to SystemC 2.3.3; SystemC 2.3.1 is fairly old.
    1 point
  28. Code itself looks fine. I ran the above on EDAplayground without problem. I also ran on MacOS 10.15.7 (Catalina) with Apple clang++ 12.0 (LLVM ) Here is a link to where I ran it: https://edaplayground.com/x/V25h SystemC 2.3.3-Accellera --- Sep 21 2020 10:55:34g++ 7.5Using C++ standard 201402Ubuntu 18.04 You might consider upgrading g++ (4.8 is pretty old). I use g++ 9.3 normally.
    1 point
  29. SystemC is a discrete event driven simulator using an approach similar to Verilog, SystemVerilog and VHDL.The coding approach assumes cooperative multitasking. This is very time efficient and more importantly simplifies the modeling aspect if you really understand it, and makes it easier to interoperate with other simulators. Immediate notification is a unique feature of SystemC that works for some models, but not all. The reasoning behind it is simple efficiency. Delayed notification (i.e., SC_ZERO_TIME) is the safest approach if you are not certain that other processes are designed to work with immediate notification. Both potentially (likely) result in additional delta cycles. I have an old presentation (with code) that graphically single steps the simulator to make its behavior easier to understand under https://github.com/dcblack/SystemC-Engine/.
    1 point
  30. @plafrattTLM2 is built to allow any protocols you like. The "base protocol" was deemed sufficient for most needs; however, TLM2 was designed specifically to allow alternatives. Furthermore, the standard provides mechanisms to keep the cost of adapters/bridges between protocols simulation efficient. [Plug - ignore if you like] The Doulos course on TLM 2.0 <https://www.doulos.com/training/systemc-tlm-20/systemc-modeling-using-tlm-20-online/> investigates the base protocol and then builds up to a module describing custom protocols.
    1 point
  31. Have a goal. Do you want to learn the design side or verification? Either way, create some small design, then a testbench to check its operation. There are a lot of great resources out there. Sometimes you can get a simulator license by taking a course. Or use the EDA Playground. Stu Sutherland has an excellent book on design with SystemVerilog. Highly recommended! Personally, I learned a lot by writing many small examples. You can do a lot in a dozen lines. I have a directory filled with little modules, most under 20 lines. If you keep it small, you can stay focused. Once you have mastered the concept, apply it to your design and testbench. Cheers, Chris Spear Mentor Graphics
    1 point
  32. Paul Floyd

    A few Valgrind issues

    More details on the other two issues systemc/misc/user_guide/chpt4.4 ==165605== Invalid write of size 8 ==165605== at 0x49FACA6: sc_core::sc_object::orphan_child_objects() (sc_object.cpp:336) ==165605== by 0x49F5D46: sc_core::sc_module::~sc_module() (sc_module.cpp:273) ==165605== by 0x406CC3: stage1_2::~stage1_2() (stage1_2.h:43) ==165605== by 0x406B95: pipeline::~pipeline() (pipeline.h:43) ==165605== by 0x406C38: pipeline::~pipeline() (pipeline.h:43) ==165605== by 0x49F5343: sc_core::sc_module_dynalloc_list::~sc_module_dynalloc_list() (sc_module.cpp:94) ==165605== by 0x4EA4236: __run_exit_handlers (in /usr/lib64/libc-2.32.so) ==165605== by 0x4EA43DF: exit (in /usr/lib64/libc-2.32.so) ==165605== by 0x4E8C1E8: (below main) (in /usr/lib64/libc-2.32.so) ==165605== Address 0x5377510 is 96 bytes inside a block of size 448 free'd ==165605== at 0x483AEDD: operator delete(void*) (vg_replace_malloc.c:584) ==165605== by 0x4071A6: stage1::~stage1() (stage1.h:43) ==165605== by 0x49F5343: sc_core::sc_module_dynalloc_list::~sc_module_dynalloc_list() (sc_module.cpp:94) ==165605== by 0x4EA4236: __run_exit_handlers (in /usr/lib64/libc-2.32.so) ==165605== by 0x4EA43DF: exit (in /usr/lib64/libc-2.32.so) ==165605== by 0x4E8C1E8: (below main) (in /usr/lib64/libc-2.32.so) ==165605== Block was alloc'd at ==165605== at 0x4839E7D: operator new(unsigned long) (vg_replace_malloc.c:342) ==165605== by 0x406EAC: f_stage1(char const*, sc_core::sc_clock&, sc_core::sc_signal<double, (sc_core::sc_writer_policy)0> const&, sc_core::sc_signal<double, (sc_core::sc_writer_policy)0> const&, sc_core::sc_signal<double, (sc_core::sc_writer_policy)0>&, sc_core::sc_signal<double, (sc_core::sc_writer_policy)0>&) (stage1.cpp:66) ==165605== by 0x406951: stage1_2::stage1_2(sc_core::sc_module_name, sc_core::sc_clock&, sc_core::sc_signal<double, (sc_core::sc_writer_policy)0> const&, sc_core::sc_signal<double, (sc_core::sc_writer_policy)0> const&, sc_core::sc_signal<double, (sc_core::sc_writer_policy)0>&, sc_core::sc_signal<double, (sc_core::sc_writer_policy)0>&) (stage1_2.h:56) ==165605== by 0x406AA1: pipeline::pipeline(sc_core::sc_module_name, sc_core::sc_clock&, sc_core::sc_signal<double, (sc_core::sc_writer_policy)0> const&, sc_core::sc_signal<double, (sc_core::sc_writer_policy)0> const&, sc_core::sc_signal<double, (sc_core::sc_writer_policy)0>&) (pipeline.h:56) ==165605== by 0x4067FB: f_pipeline(char const*, sc_core::sc_clock&, sc_core::sc_signal<double, (sc_core::sc_writer_policy)0> const&, sc_core::sc_signal<double, (sc_core::sc_writer_policy)0> const&, sc_core::sc_signal<double, (sc_core::sc_writer_policy)0>&) (pipeline.cpp:55) ==165605== by 0x4048D9: sc_main (main.cpp:58) ==165605== by 0x49F1E8C: sc_elab_and_sim (sc_main_main.cpp:89) ==165605== by 0x49F1CCE: main (sc_main.cpp:36) memcheck is saying that in this code [sc_object.cpp void sc_object::orphan_child_events()] for( ; it != end; ++it ) { (*it)->m_parent = NULL; simcontext()->add_child_object(*it); } the child object has already been deleted, so it is writing to deleted memory. I assume that stage1 should be destroyed after stage1_2. Should pipeline::stage1_2 be a pointer allocated with SC_NEW so that the destruction gets done in the right order? If so it's an issue with the testcase so not a very serious problem. And the last problem tlm/bus_dmi ==166842== Thread 5: ==166842== Conditional jump or move depends on uninitialised value(s) ==166842== at 0x4278D8: tlm_utils::simple_target_socket_b<ExplicitATTarget, 32u, tlm::tlm_base_protocol_types, (sc_core::sc_port_policy)0>::bw_process::nb_transport_bw(tlm::tlm_generic_payload&, tlm::tlm_phase&, sc_core::sc_time&) (simple_target_socket.h:157) ==166842== by 0x415358: ExplicitATTarget::beginResponse() (ExplicitATTarget.h:133) ==166842== by 0x4A0B504: sc_core::sc_process_b::semantics() (sc_process.h:685) ==166842== by 0x4A11C21: sc_core::sc_thread_cor_fn(void*) (sc_thread_process.cpp:117) ==166842== by 0x49EABB0: sc_core::sc_cor_pthread::invoke_module_method(void*) (sc_cor_pthread.cpp:127) ==166842== by 0x4E493F8: start_thread (in /usr/lib64/libpthread-2.32.so) ==166842== by 0x4F65902: clone (in /usr/lib64/libc-2.32.so) ==166842== Uninitialised value was created by a stack allocation ==166842== at 0x40A8EB: sc_main (bus_dmi.cpp:37) ==166842== ==166842== Thread 1: ==166842== Conditional jump or move depends on uninitialised value(s) ==166842== at 0x429158: tlm_utils::simple_target_socket_b<SimpleATTarget2, 32u, tlm::tlm_base_protocol_types, (sc_core::sc_port_policy)0>::bw_process::nb_transport_bw(tlm::tlm_generic_payload&, tlm::tlm_phase&, sc_core::sc_time&) (simple_target_socket.h:157) ==166842== by 0x413A65: SimpleATTarget2::beginResponse() (SimpleATTarget2.h:145) ==166842== by 0x4A0B504: sc_core::sc_process_b::semantics() (sc_process.h:685) ==166842== by 0x4A0B788: sc_core::sc_method_process::run_process() (sc_method_process.h:305) ==166842== by 0x4A0CFA3: sc_core::sc_simcontext::crunch(bool) (sc_simcontext.cpp:486) ==166842== by 0x4A08D19: sc_core::sc_simcontext::simulate(sc_core::sc_time const&) (sc_simcontext.cpp:887) ==166842== by 0x4A0AB61: sc_core::sc_start(sc_core::sc_time const&, sc_core::sc_starvation_policy) (sc_simcontext.cpp:1718) ==166842== by 0x4A0AC8C: sc_core::sc_start() (sc_simcontext.cpp:1752) ==166842== by 0x40AEBF: sc_main (bus_dmi.cpp:76) ==166842== by 0x49F1E8C: sc_elab_and_sim (sc_main_main.cpp:89) ==166842== by 0x49F1CCE: main (sc_main.cpp:36) ==166842== Uninitialised value was created by a stack allocation ==166842== at 0x40A8EB: sc_main (bus_dmi.cpp:37) ==166842== This is a very straightforward missing initialization, fixed with the following change diff --git a/src/tlm_utils/simple_target_socket.h b/src/tlm_utils/simple_target_ socket.h index 7e4c3a19..c3bd240f 100644 --- a/src/tlm_utils/simple_target_socket.h +++ b/src/tlm_utils/simple_target_socket.h @@ -68,6 +68,7 @@ public: : base_type(n) , m_fw_process(this) , m_bw_process(this) + , m_current_transaction(NULL) { bind(m_fw_process); }
    1 point
  33. This part is wrong: for ( int i=0; i<N ; i++){ for ( int j=0; j<NB_elements_trans ; j++){ i_adder = new adder("i_adder"); i_adder->in[j](sig_data[i][j]); } i_adder->out(sig_add); } You create N x NB_elements_trans i_adder elements and on each of them you only connect 1 of 4 in ports. I guess you mean: for ( int i=0; i<N ; i++){ i_adder = new adder("i_adder"); for ( int j=0; j<NB_elements_trans ; j++){ i_adder->in[j](sig_data[i][j]); } i_adder->out(sig_add); } A few remarks: you create a memory leak by assigning objects created with new to the same variable you should not use raw pointer. Use C++11 unique_ptr instead Name you SystemC objects, this helps debugging. C++11 makes it easy witn in-class constructors, e.g.: sc_signal<double> sig_add{"sig_add"}; don't use plain C-style arrays, uses either std::array or std::vector. These provide range checking capabilities and help finding out-of-bounds problems don't use C or C++arrays for SystemC objects. Use sc_core::sc_vector instead use proper formatting, this eases reading (an IDe or clang-format is your friend). Keep in mind: code is a hundret times more often read than written!
    1 point
  34. Hello @Beginner_KOR, You can follow a similar discussion here: Hope this helps. Regards, Ameya Vikram Singh
    1 point
  35. Actually you cannot use sc_core::sc_fifo for this as it takes ownership of the data which doesn't play well with the concepts of the generic payload. But there are event queues in tlm_utils for this (tlm_utils::peq_with_get and tlm_utils::peq_with_cb_and_phase).
    1 point
  36. In the constructor list you would provide a creator function. This is a functor(a function pointer, a std::function object, a Functor classinstance, a lambda function, ...) which accepts a char const* and a size_type and returns a constructed object. In your case it would look like (C++11): class example: public sc_core::sc_module { public: sc_core::sc_vector<sc_core::sc_fifo<unsigned>> fifos; example(sc_core::sc_module_name nm, unsigned outputs) : sc_core::sc_module(nm) , fifos("fifos", outputs, [](char const* name, unsigned i)->sc_core::sc_fifo<unsigned> { return new sc_core::sc_fifo<unsigned>(5000); } { // some construction code } }
    1 point
  37. SystemC FIFO's represent hardware and as such may only be created during construction of a model. After elaboration closes, you are not allowed to add more fifos. None of your code examples above are complete, so it is fairly hard to give you a complete answer. Perhaps you could put your design on https://edaplayground.com and share a link with us. For details on phases of SystemC (e.g. elaboration) see IEEE-1666-2011.pdf, which you can obtain through Accellera.org.
    1 point
  38. Hello @Beginner_KOR, I would recommend going through details on SystemC TLM modeling using the following resources in no particular order: SystemC Standard document: IEEE 1666-2011(Must read) SystemC from Ground Up 2nd Edition by @David Black. https://github.com/dcblack/SCFTGU_BOOK/ Looking at SystemC TLM examples in the SystemC Sources: https://github.com/accellera-official/systemc/tree/master/examples/tlm SystemC TLM-2.0 examples on EDA Playground: https://www.edaplayground.com/playgrounds?searchString=&language=C%2B%2B+only&simulator=&methodologies=&_libraries=on&_svx=on&_easierUVM=on&curated=true&_curated=on For specific reference to AHB or APB Specific Implementation you could look into: https://socrocket.github.io/modeling.html#modeling6_3 Regarding the maximum compatibility for SystemC TLM models, I would recommend going with TLM-2.0 base protocols. Hope it helps. Regards, Ameya Vikram Singh
    1 point
  39. 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.
    1 point
  40. Eyck

    tlm to pin converter

    Well, sc_fifo is not TLM. For your example the basic question is: what is the protocol on fifo_out? Should it be clock-based? Valid-Ready signaling? So your queastion and example is too generic and broad. If you are looking for an example to translate from TLM2.0 to pin level of an Amba AHB protocol you may have a look here: https://git.minres.com/SystemC/SystemC-Components/src/branch/master/incl/tlm/ahb/bfm and https://git.minres.com/SystemC/SystemC-Components/src/branch/master/src/tlm_ahb_bfm_initiator.cpp as well as https://git.minres.com/SystemC/SystemC-Components/src/branch/master/src/tlm_ahb_bfm_target.cpp. They implement TLM2.0 to pin and pin to TLM2.0
    1 point
  41. Hi Folks, Are there good open source libraries out there to model (AT/FT style) SoC components (memories, buses, simple nocs, dma engines, registers which can be decoded off of APB) ? Upon some searching I came across - 1. scml/scml2 - https://gitlab.larc-nthu.net/rgly/scml/-/tree/6cb6356704245b9c17f816ba957f1a0971d76a67 (does not offer bus components) 2. System C components - https://github.com/Minres/SystemC-Components (offers bus components - but the buses do not seem to have non block transfer interface) 3. VCML - https://github.com/janweinstock/vcml (offers bus components - but the buses do not seem to have non block transfer interface) Any recommendations ? I am particularly interested in bus models (ring architecture, simple noc and bus with protocols like OCP, APB) and registers which are addressed over APB bus. Thanks.
    1 point
  42. Check clause 5.11 of IEEE Std 1666-2011 for the member functions of the sc_time class. sc_time::value() will return the underlying integer representation of the time value, which has to be interpreted together with the set discrete time resolution. sc_time::to_seconds() returns a double value representing the time value in seconds.
    1 point
  43. what are the major differences between sc_port and sc_export?
    1 point
  44. Actually, it adds a lot of value. std::array can be passed by reference in a function call and the function can then determine the proper size of the array. This is much better than passing pointers, the C standard. You can also copy an array, which should be synthesizable, which reduces coding and greatly improves readability. It should be possible to implement some #include <algorithm>s on std::array too. Also, you can have bounds checking for additional safety; although, that aspect is probably not synthesizable. Additionally, constexpr should be quite helpful for the synthesis aspect.
    1 point
  45. TLM payload is used for untyped raw data transfers. Data format is usually a property of device. Let's consider an example: Initiator is CPU model, and target is Convolution filter accelerator. Accelerator accepts a 2d matrix (2d array) of coefficients as an input. Documentation of accelerator must specify a binary format of data, for example: coefficients are stored in row-major order, each coefficient is 8-byte signed integer. Using this documentation initiator converts 2d array into a raw data of tlm payload. And device model converts raw data back into 2d array. This is how it is usually done.
    1 point
  46. Hello @re1418ma, You can look at this example: http://forums.accellera.org/topic/5678-clock-to-q-propagation-delay/?do=findComment&comment=13657 Or this one which shows how to add delay in full adder: http://forums.accellera.org/topic/5715-delaying-simulated-execution/?do=findComment&comment=13844 Hope it helps. Regards, Ameya Vikram Singh
    1 point
  47. SystemC follows event driven simulation semantics to simplify hardware modeling. In part, this means using a cooperative multi-tasking model rather than a modern pre-emptive model. In this respect, SystemC is like SystemVerilog and VHDL. This makes it easier to focus on the modeling aspects rather than worrying about mutexes, volatility and other interactions due to multicore and parallel processes. Advanced SystemC users can use OS threads for some tasks, but the synchronization aspects are up to the programmer. So SC_THREAD's are not pre-emptive (nor are SC_METHOD processes) and hence a straightforward SystemC model is single core single threaded from an OS/software point of view. Additionally, you should be aware that the SystemC scheduler is not thread-safe for the most part. If you make use of async_request_update(), you can use multicore and parallel processes to interact with SystemC events. This assumes you are an expert programmer and proficient with C++ (not for beginners). There have been and are some efforts underway to standardize parallelization in SystemC, but it is a volunteer effort and you need to be on the SystemC LWG group to participate. Some commercial entities have developments underway, but keeping those closed for the time being. Always keep in mind that SystemC is not freeware, but was created as part of a commercial coalition to standardize modeling across/between companies. Don't think of SystemC as a free simulator. Also, SystemC is often mistaken as a competitor/alternative to SystemVerilog/VHDL, which it is NOT. SystemC was intended for high-level modeling and abstractions above RTL. The ability to co-simulate with RTL is a requirement for some of the use-cases. SystemC is used quietly by many large corporations to augment specification and verification. It differs from the other languages in that it uses an off-the-shelf C++ compiler and has no requirement of a specialized compiler. This benefits companies with huge software development teams using SystemC Virtual Platform models for early software development. The downside of this approach is the C++ compiler has no understanding of the SystemC domain and has no way to make optimizations that SystemVerilog/VHDL do (e.g. clocks). That is one reason that SystemC coders are advised to avoid explicit clock models to gain performance. Keep the design at as high a level of abstraction as you can.
    1 point
  48. tymonx

    Unit testing with gtest

    You must create all necessary SystemC signals, SystemC modules and make connection between them before you run any test in gtest. This require to create own gtest_main.cc implementation. Naturally in SystemC you must put everything in sc_main() function. For this, I would use registry design pattern. First create registry class (registry + factory + singleton). This class will be responsible for storing registered constructors using dynamic allocation with new and smart pointer in lambda expression (see factory::add class). Create all objects using factory::create() method before running all tests. Then you can get object using factory::get() method in you test execution. factory.hpp #ifndef FACTORY_HPP #define FACTORY_HPP #include <map> #include <string> #include <memory> #include <functional> class factory { public: static factory& get_instance(); template<typename T, typename ...Args> class add { public: add(Args&&... args); add(const std::string& name, Args&&... args); }; template<typename T> static T* get(const std::string& name = ""); void create(); void destroy(); private: using destructor = std::function<void(void*)>; using object = std::unique_ptr<void, destructor>; using constructor = std::function<object(void)>; factory(); factory(const factory& other) = delete; factory& operator=(const factory& other) = delete; void add_object(const std::string& name, constructor create); void* get_object(const std::string& name); std::map<std::string, constructor> m_constructors; std::map<std::string, object> m_objects; }; template<typename T, typename ...Args> factory::add<T, Args...>::add(Args&&... args) { add("", args...); } template<typename T, typename ...Args> factory::add<T, Args...>::add(const std::string& name, Args&&... args) { factory::get_instance().add_object(name, [args...] () -> object { return object{ new T(std::forward<Args>(args)...), [] (void* obj) { delete static_cast<T*>(obj); } }; } ); } template<typename T> auto factory::get(const std::string& name) -> T* { return static_cast<T*>(factory::get_instance().get_object(name)); } #endif /* FACTORY_HPP */ factory.cpp #include "factory.hpp" #include <stdexcept> auto factory::get_instance() -> factory& { static factory instance{}; return instance; } factory::factory() : m_constructors{}, m_objects{} { } void factory::create() { for (const auto& item : m_constructors) { m_objects[item.first] = item.second(); } } void factory::destroy() { m_objects.clear(); } void factory::add_object(const std::string& name, constructor create) { auto it = m_constructors.find(name); if (it == m_constructors.cend()) { m_constructors[name] = create; } else { throw std::runtime_error("factory::add(): " + name + " object already exist in factory"); } } auto factory::get_object(const std::string& name) -> void* { auto it = m_objects.find(name); if (it == m_objects.cend()) { throw std::runtime_error("factory::get(): " + name + " object doesn't exist in factory"); } return it->second.get(); } Create your own version of gtest_main.cc implementation. Call factory::create() method to create all SystemC signals and SystemC modules before running any tests RUN_ALL_TESTS(). Because factory class is a singleton design pattern, call factory::destroy() method after finishing all tests to destroy all created SystemC objects. main.cpp #include "factory.hpp" #include <systemc> #include <gtest/gtest.h> int sc_main(int argc, char* argv[]) { factory::get_instance().create(); testing::InitGoogleTest(&argc, argv); int status = RUN_ALL_TESTS(); factory::get_instance().destroy(); return status; } Then define dut class in your test than will create SystemC signals and SystemC modules. In constructor do connection between created SystemC signals and modules. Register defined dut class to registry object using global constructor like this factory::add<dut> g. After than you can get your dut object using simple factory::get<dut>() method. test.cpp #include "my_module.h" #include "factory.hpp" #include <gtest/gtest.h> #include <systemc> class dut { public: sc_core::sc_clock aclk{"aclk"}; sc_core::sc_signal<bool> areset_n{"areset_n"}; sc_core::sc_signal<bool> in{"in"}; sc_core::sc_signal<bool> out{"out"}; dut() { m_dut.aclk(aclk); m_dut.areset_n(areset_n); m_dut.in(in); m_dut.out(out); } private: my_module m_dut{"my_module"}; }; static factory::add<dut> g; TEST(my_module, simple) { auto test = factory::get<dut>(); test->areset_n = 0; test->in = 0; sc_start(3, SC_NS); test->areset_n = 1; test->in = 1; sc_start(3, SC_NS); EXPECT_TRUE(test->out.read()); } For more inspiration, you can check my logic library for SystemC verification: https://github.com/tymonx/logic
    1 point
  49. Hello @katang, Here is a modified source for Bit_Adder.h which emulates the delay between component/modules: #ifndef BIT_ADDER_H_ #define BIT_ADDER_H_ #include <systemc> #include <queue> template<typename T = bool> SC_MODULE(BIT_ADDER) { public: sc_core::sc_in<T> a, b, cin; sc_core::sc_out<T> sum, cout; SC_CTOR(BIT_ADDER): a("a") , b("b") , ci("cin") , sum("sum") , cout("cout") , delay(sc_core::sc_time(2, sc_core::SC_NS)) , eqSum("eqSum") , eqCarry("eqCarry") { SC_METHOD(do_add); sensitive << a << b << cin; dont_initialize(); SC_METHOD(drive_sum); sensitive << eqSum; dont_initialize(); SC_METHOD(drive_carry); sensitive << eqCarry; dont_initialize(); } void do_add(void) { T valA = a.read(); T valB = b.read(); T valCi = cin.read(); T tmpCo = (valA & valB) | (valB & valCi) | (valA & valCi); T tmpSum = valA ^ valB ^ valCi; coq.push(tmpCo); sumq.push(tmpSum); eqSum.notify(delay); eqCarry.notify(delay); } void drive_sum(void) { T valSum = sumq.front(); sum.write(valSum); sumq.pop(); } void drive_carry(void) { T valCarry = coq.front(); cout.write(valCarry); coq.pop(); } private: sc_core::sc_time delay; sc_core::sc_event_queue eqSum; sc_core::sc_event_queue eqCarry; std::queue<T> sumq; std::queue<T> coq; }; // BIT_ADDER #endif // BIT_ADDER_H_ This should be drop-in replacement for your module. One thing you will have to change is the declaration where it would change something from: BIT_ADDER bitAdder to: BIT_ADDER<sc_logic> bitAdder Let us know if you need further clarification on how the module behavior is modeled. Regards, Ameya Vikram Singh
    1 point
  50. Rahul, after fixing the missing '$' at the beginning of your vcd dump, I got the following error on GTKwave: GTKWave Analyzer v3.3.49 (w)1999-2013 BSI Near byte 206, $VAR parse error encountered with 'SystemC.Enable' Near byte 252, $VAR parse error encountered with 'SystemC.output' No symbols in VCD file..nothing to do! As you can see, there is an error in your VCD file (at least according to GTKwave): You use spaces in your signal names. Replace those with '_' or something similar, and your VCD viewer should be happy. hth, Philipp
    1 point
×
×
  • Create New...