Jump to content

Leaderboard


Popular Content

Showing content with the highest reputation since 05/19/2018 in Posts

  1. 3 points
    Well, this topic could fill an entire book... If you implement a model the first question you should as is: What is the purpose of the model? Which questions should the simulation of the model answer? Looking at architectural exploration which goes quite often hand in hand with performance analysis the question is: does my HW/SW split and my HW partitioning satisfy my perfomance requirements (wrt. latency, thru-put, compute.efficiency, power,...). In this case you usually do not need to implement a particular functionality in detail rather something that 'behaves like' in terms of your requirements. E.g. if you need to check that your communication scheme (buses, arbiters, bridges etc.) fulfills the needed band with you use traffic generators but have a fairly accurate bus model, sometimes even at AT. And you need to implement the mechanisms to observer and extract the needed performance indicators to allow the analysis For software development the requirements are different. Here the maximum simulation speed is required so whereever possible you take short cuts. Bus transaction are not modelled anymore rather DMI is used (of course if functionality allows to do so e.g. when reading from/writing to a memory) and the entire model may run in LT mode which allowes parts to independently advance in time. Peripheral units may be modelled register-accurate but with out real functionality, i.e. a system control unit does not follow the needed scheme if changing e PLL frequency and alike. This might give you some high-level clue. There are many more things to it but all of them depend on the answer to the initial questions. Maybe the DCVon Europe 2017 tutorial on virtiual protorypes might provide a few more answers. You may find a PDF version of it at the MINRES site in the Publications and Papers section or at https://minres.com/downloads/VP_Tutorial_DVCon-2017.pdf as well as at the DVCon Europe website https://dvcon-europe.org/conference/history Best regards -Eyck
  2. 2 points
    David Black

    Seeking Feedback on Datatypes

    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.
  3. 2 points
    Hi, I'm not an implementer of the reference simulator but as far as I can judge the re-throw is used to find a more specific type of exception (since sc_elab_and_sim() just uses a catch-all) and uses sc_handle_exception() to convert it into an sc_report so it can be handled by the SystemC reproting system. Actually I agree it would be better to handle it directly in sc_elab_and_sim() but this would duplicate code. A side note rgd. debugging: if you use gdb there is a command 'catch throw' which stops execution right at the point where the (original) exception is thrown. This comes pretty handy in such cases. Best regards
  4. 2 points
    Hi Ivan, instead of referring to the very old 2.01. LRM, I suggest to check the IEEE Std. 1666-2011 for SystemC, which could can download at no cost (sponsored by Accellera) via https://standards.ieee.org/findstds/standard/1666-2011.html. This document includes the normative answers to all of your questions. Yes, see section 5.10.8 of the aforementioned standard. Kind of, yes. This is called "time out", see section 4.2(.1) of the standard. The order to execution of processes in the runnable queue is entirely implementation-defined. See section 4.2.1.2. Hope that helps, Philipp Disclaimer: I haven't checked all of your post for correctness and focused on the questions instead. .
  5. 2 points
    Yes, this change in behaviour of SystemC 2.3.2 with respect to SystemC 2.3.1 is intentional to better conform to IEEE Std 1666-2011, which states in clause 6.4.4 about signal writes under the SC_MANY_WRITERS policy: This fix by @Philipp A Hartmann is documented in the RELEASENOTES of SystemC 2.3.2:
  6. 2 points
    Hello All, I ran static analysis on latest SystemC library [For Fun]. clang-tidy report looks fine (I gave a very fast look). clang++ --analyze produced followed warnings which I want to point out: warning: Path diagnostic report is not generated. Current output format does not support diagnostics that cross file boundaries. Refer to --analyzer-output for valid output formats In file included from ../src/sysc/datatypes/int/sc_int_base.cpp:66: ../src/sysc/datatypes/int/sc_int_base.h:574:22: warning: The result of the left shift is undefined because the left operand is negative m_val = ( m_val << m_ulen >> m_ulen ); ~~~~~~^~~~~~~~~ 1 warning generated. ../src/sysc/utils/sc_mempool.cpp:252:59: warning: Division by zero int which_allocator = cell_size_to_allocator[(sz - 1) / increment + 1]; ~~~~~~~~~^~~~~~~~~~~ 1 warning generated. warning: Path diagnostic report is not generated. Current output format does not support diagnostics that cross file boundaries. Refer to --analyzer-output for valid output formats warning: Path diagnostic report is not generated. Current output format does not support diagnostics that cross file boundaries. Refer to --analyzer-output for valid output formats warning: Path diagnostic report is not generated. Current output format does not support diagnostics that cross file boundaries. Refer to --analyzer-output for valid output formats ../src/sysc/utils/sc_string.cpp:181:19: warning: Use of memory after it is freed return strlen(rep->str); ^~~~~~~~ ../src/sysc/utils/sc_string.cpp:242:9: warning: Use of memory after it is freed if (--(rep->ref_count) == 0) ^~~~~~~~~~~~~~~~~~ ../src/sysc/utils/sc_string.cpp:357:9: warning: Use of memory after it is freed if (rep->ref_count > 1) { ^~~~~~~~~~~~~~ 3 warnings generated. warning: Path diagnostic report is not generated. Current output format does not support diagnostics that cross file boundaries. Refer to --analyzer-output for valid output formats In file included from ../src/sysc/kernel/sc_simcontext.cpp:32: In file included from ../src/sysc/kernel/sc_simcontext_int.h:37: ../src/sysc/kernel/sc_runnable_int.h:464:18: warning: Called C++ object pointer is null m_methods_pop = m_methods_push_head->next_runnable(); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Even if these will not pose a problem for running simulations, I will get my sanitizer and other tools irked out. Following is the script if anybody want to try. set x = `find ../src -name "*.cpp"` foreach item ($x) /home/sumit/local/clang/bin/clang-tidy \ -checks='*' \ `echo ${item}` \ -extra-arg=-std=c++17 -- -I ../src end /home/sumit/local/clang/bin/clang++ --analyze -std=c++17 -I ../src \ `echo $x` Please let me know, if there is further questions. Regards, Sumit
  7. 2 points
    Hi Aarthi, if you just need to get the currently active module when hitting a breakpoint in you C++ code you might use the following command (assuming you use gdb): x sc_core::sc_get_current_process_b()->get_parent()->name() (see also here: https://stackoverflow.com/questions/18078226/how-to-get-sc-module-name-of-the-current-running-module#18123785) What it does is it calles the SystemC kernel function sc_get_current_process_b() which returns a pointer to sc_process_b (the base class of of sc_method_process and sc_thread_process). Inheriting from sc_obejt it also has a name() method so you could also do x sc_core::sc_get_current_process_b()->name() which just returns the full hierarchical name of the process. HTH -Eyck
  8. 2 points
    Hi Kevin, if you check here https://github.com/Minres/SystemC-Components/blob/master/incl/scc/utilities.h there are three macros which make live easier: #define TRACE_VAR(F, X) sc_core::sc_trace(F, X, std::string(this->name()) + "." #X) #define TRACE_ARR(F, X, I) sc_core::sc_trace(F, X[I], (std::string(this->name()) + "." #X "(" + std::to_string(I) + ")").c_str()); #define TRACE_SIG(F, X) sc_core::sc_trace(F, X, X.name()) They can be used with local variables and arrays as well with SystemC objects providing the name() funtion. This way tracing a signal becomes as easy as (assuming _STATE_ being a signal or port): TRACE_VAR(_trace_, top.dpu.idu.weight_reader.m_traffic_gen._STATE_); Pls. note: the first 2 macros are assumed to be used within a sc_module. HTH -Eyck
  9. 2 points
    David Black

    make check return fail

    I am able to reproduce the problem and will attempt a fix. Unless you are using async_request_update() in your code, you can safely ignore this problem for now. CORRECTION: While there is a bug with the following deprecated feature issue, this does not solve the problem. Stay tuned for a real fix. There is a bug in the implementation of SystemC due to Apple removing support for POSIX sem_init, which is a non-required API by the POSIX standard. See <https://stackoverflow.com/questions/1413785/sem-init-on-os-x/24617282> for details. [Pure speculation: I suspect the reason for removing support was that Apple has recently moved to an all 64-bit coding model. Potentially because they are positioning themselves to be able to port quickly to Arm v8A lacking Aarch32 on certain hardware.] When building on OSX using Cmake I noticed a clue: I use the adage, "A warning is usually a potential bug leading to a real error." Never ignore warnings from compilations. Yes, I know there is a lot of code out there with superfluous warnings. Shame on them for leaving them in. So if you see a warning, track it down. If it is truly a don't care (rarely), then it can be overridden with a #pragma. Almost all warnings can be fixed with proper coding. I am going to attempt a fix to sc_host_semaphore.h, but if you're in a hurry go to Linux.
  10. 2 points
    When reading the signal 'inter' right after writing to it (line 25 of the referenced code) you read the current value and not the scheduled (new) value. Writes to signals (as part of methods or threads) are executed in the evaluation phase of the simulation kernel while the value is assigned during the update phase of the kernel (see also https://ptolemy.berkeley.edu/projects/embedded/research/hsc/class/ee249/lectures/l10-SystemC.pdf?46). If you read a signal in the same evaluation phase you are writing to it, you will always get the current value, not the new (scheduled) value. If you have several assignments to the signal the last one will always win. I.e. lets assume you have a signale and a thread like: void thread(){ sig.write(42); wait(0, SC_NS); // advance by 1 delta cycle sig.write(1); cout<<"Sig is "<<sig.read()<<std::endl; sig.write(2); cout<<"Sig is "<<sig.read()<<std::endl; sig.write(3); cout<<"Sig is "<<sig.read()<<std::endl; wait(SC_ZERO_TIME); // same as the last wait(), advance by 1 delta cycle cout<<"Sig is "<<sig.read()<<std::endl; } you will get the output: Sig is 42 Sig is 42 Sig is 42 Sig is 3 because the update to sig will only happen during the wait() call. I hope this answers your question.
  11. 2 points
    Hi @vasu_c, thanks for finding this. The patch below should fix your issue if you want to try it out early. Apologies for the inconvenience. --- a/src/sysc/packages/qt/md/aarch64.s +++ b/src/sysc/packages/qt/md/aarch64.s @@ -59,8 +59,10 @@ qt_blocki: mov x0, sp // arg0 = old_sp mov sp, x3 // sp = new_sp + sub sp, sp, 160 // (*helper)(old_sp, a0, a1) blr x4 + add sp, sp, 160 // Callee-saved ldp x29, x30, [sp, #-16] // frame, link
  12. 1 point
    SystemC is single threaded, you don't need std::mutex. However SystemC does not guarantee any order for processes executed in the same delta cycle. SystemC is a discrete-event simulator, and I suggest you to learn the concepts of simulation semantics from Paragraph 4 "Elaboration and simulation semantics" of IEEE-1666 SystemC standard. The purpose of primitive channels, like sc_signal, is to remove non-determinism by separating channel update request from actual update of value into two different simulation phases. But it only works if there is a single writing process during a delta cycle. In your case if initiator and responder threads are executed on same cycle, they both will read the same "current value" of signal. Initiator will request to set signal value to (valid = 1, ready = 0) and responder will request to set it to (valid = 0, ready = 1). Since there is no guarantee on order between processes, you will either get (1,0) or (0,1) on the next cycle.
  13. 1 point
    Roman Popov

    using gtkwave

    Your code is not correct. Why did you put next_trigger(5, SC_NS) inside a method? Remove it, and you will get correct waveform for and gate.
  14. 1 point
    Eyck

    using gtkwave

    Actually SystemC provided sc_trace(...) functions where you register your signals and variables for tracing. Running the simulation yields a .vcd file which you can open in gtkwave. You may have a look into https://github.com/Minres/SystemC-Components-Test/blob/master/examples/transaction_recording/scv_tr_recording_example.cpp In sc_main() you will find sc_trace_file *tf = sc_create_vcd_trace_file("my_db"); sc_trace_file *tf = sc_create_vcd_trace_file("my_db"); This opens the waveform database. At the end you have to call sc_close_vcd_trace_file(tf); to properly close the database. 'tf' is a handle to the database, if you follow the code you will see how to trace signals (or variables), Best
  15. 1 point
    AmeyaVS

    Behavioral XOR Gate with Delay

    Hello @re1418ma, This has been already discussed before here: http://forums.accellera.org/topic/5715-delaying-simulated-execution/ Hope it helps and if you have further questions please feel to ask. Regards, Ameya Vikram Singh
  16. 1 point
    Hello everyone, first of all I apologize if the post is too big and I know sometimes people get discouraged to read big posts. On the other hand I spent quite some time trying to make the post as clear as possible for the reader. So please do not get discouraged :). My SystemC version: SystemC 2.3.1 My operating System: Ubuntu 16.04 I am trying to understand how SystemC simulator works, and for that I ran the following code: SC_MODULE(EventNotifications) { sc_event evt1; void p1() { evt1.notify(10, SC_NS); evt1.notify(5, SC_NS); evt1.notify(); evt1.notify(0, SC_NS); wait(10, SC_NS); evt1.notify(5, SC_NS); wait(10, SC_NS); } void p2() { wait(10, SC_NS); evt1.cancel(); evt1.notify(); wait(10,SC_NS); } void p3() { cout << "evt1 is activated at " << sc_time_stamp() << endl; } SC_CTOR(EventNotifications){ SC_THREAD(p1); SC_THREAD(p2); SC_METHOD(p3); sensitive << evt1; dont_initialize(); } }; I referred to the SystemC Language Reference Manual 2.0.1: http://homes.di.unimi.it/~pedersini/AD/SystemC_v201_LRM.pdf and in my explanation down below, I used the following abbreviations: R = {} - list of runnable processes, D = {} - list of processes that have been notified using delta notifications, T = {} - list of processes where timed notification has been used e.g. event.notify( >0, SC_NS) 2.4.1 Scheduler Steps at page 6 from the SystemC Language Reference Manual 2.0.1 was used for the following reasoning of how this code works: Initialize phase: We initialize all the processes that are ready to run. Process p3 at the beginning will not be runnable due to dont_initialize command. So only p1 and p2 processes runnable, as a result R = {p1, p2} at the end of initialize phase. Now we go to the evaluation phase. We start with simulation time equal to 0ns. Simulation time = 0 ns Evaluation phase (delta cycle = 0): We have at the beginning R = {p1, p2}, D = {} (empty list) and T = {}. Let's say scheduler decides to execute p1 first, so p1 gets removed from R, effectively R = {p2}. Then we execute 1st timed notifications evt1.notify(10, SC_NS), after that we have evt1.notify(5, SC_NS), since 5ns is earlier than 10ns, only 5ns will be remembered so we have T = {p3}. Next statement is evt1.notify() which is immediate notification, and will overwrite the previous notification evt1.notify(5, SC_NS). Immediate notification is put into the list p3, R ={p3}, and T = {}. Next statement is evt1.notify(0, SC_NS), so p3 will be put in the list D. So now we have R = {p3}, D = {p3}, T ={}. Question 1: if I swapped two statements evt1.notify(0, SC_NS) and evt1.notify() here, will the delta notification will be removed? In my opinion only evt1.nofity() will be remembered: From page 128 of the manual: "A given sc_event object can have at most one pending notification at any point. If multiple notifications are made to an event that would violate this rule, the “earliest notification wins” rule is applied to determine which notification is discarded." As a result I would have R = {p3, p2}, D = {}, T = {}. Now we encounter the wait(10, SC_NS) and p1 is put to wait. Question 2: Since I we have wait(10, SC_NS), does that mean that the process p3 will be put in separate list/queue of sleep processes? Let's call it list S, so we would have S = {p1} effectively? Next let's say scheduler decides to run p2, so we remove p2 from the R list and we have R = {p3}. There we encounter wait(10, SC_NS), and p2 gets into S list, S = {p1, p2}. Now we have R = {p3} and p3 gets executed, so immediate notification gets executed at simulation time 0 ns as 1st console output indicates. Now method p3 exits, and list R is empty, R = {}, so we go to update phase. Update phase (delta cycle = 0): Nothing to be updated. We just go to the next delta cycle phase. Next delta cycle phase(delta cycle = 0): We increment delta cycle, and check all the contents of list D and put them in the list R. In our case D = {p3}, thus R = {p3}. Now we go back to evaluation phase. Evaluation phase(delta cycle = 1): We run only p3, here so the delta notification happens at simulation time 0 ns + 1 delta cycle. R = {}, we go to the update phase. Update phase (delta cycle = 1): Nothing to be updated. Go to next delta cycle phase. Next delta cycle phase(delta cycle = 1): We increment delta cycle, but since D = {}, we go to the increase simulation time phase. Increase simulation time phase (delta cycle = 2): From the page 6: "If there are no more timed event notifications, the simulation is finished. Else, advance the current simulation time to the time of the earliest (next) pending timed event notification." Now back to my Question 2, since we T = {}, that would mean that we have no timed event notifications, and based on reference manual simulation should be finished, which is not the case here if you run the code. So from my understanding, the processes that were called with wait operation, will not be put in the "list of sleep processes" but instead they will be put to either list T or D. I think in case wait(>0, SC_NS), process gets put into the T list, and if wait(0, SC_NS) is called process should be put into the D list. So in our case T = {p1, p2}? We increase simulation time to the earliest 10 ns, and contents of list T = {p1, p2} are put into the list R = {p1, p2}. and we go to the next evaluation phase. Simulation time = 10 ns: Evaluation phase (delta cycle = 0): Here we can either run p1 or p2. Let's say p2 is run first, and we encounter evt1.cancel(), since there are no pending events nothing will happen. Then we execute evt1.notify(), and p3 gets into the list R, so R = {p1, p3}. Then wait encountered, so T = {p2}. Now let's say scheduler decides to execute p3, and then immediate notification happens at simulation time of 10 ns. Now R = {p1}, so p1 gets executed and there we have evt1.notify(5, SC_NS), so p3 gets into the list T = {p2, p3}. Then we execute wait(10, SC_NS), and p1 sleeps again. So T = {p2, p3, p1}. Since R = {0}, we go to update phase. Update phase (delta cycle = 0): Nothing to be updated, so we go to the next phase. Next delta cycle phase (delta cycle = 0): We increment delta cycle. Nothing in list D, so we go to the next phase. Increase simulation time phase (delta cycle = 1): We put contents of T into R, thus R = {p2, p3, p1}, and we increment time to the earliest pending notification, since we had evt1.notify(5, SC_NS) and threads slept for 10 ns, we chose 5 ns. So simulated time is increased to 15 ns. We again go to the evaluation phase. Simulation time = 15 ns: Evaluation phase (delta cycle = 0): Here R = {p2, p3, p1}, so let's say we execute p3 first, as result timed notification evt1.notify(5, SC_NS), happens at simulated time 15 ns. Now R = {p2, p1}, and p1 executes, since nothing after last wait statement thread terminates. Same situation for p2, so p2 terminates. R ={} go to next phase. Update phase (delta cycle = 0): Go to next phase. Next delta cycle phase (delta cycle = 0): Delta cycle updates, since D = {}, we go to the next phase Increase simulation time phase (delta cycle = 1): Since T = {}, nothing to be simulated and simulation ends. So this would explain the following result I got outputted on the console: evt1 is activated at 0 s evt1 is activated at 0 s evt1 is activated at 5 ns evt1 is activated at 10 ns I tried to check my assumption that when wait(0, SC_NS) gets called in some process, the process will be put in the D list. So I ran this code: SC_MODULE(DeltaTimeWait) { void p1(void) { while (true) { cout << "p1: " << sc_time_stamp() << endl; wait(0, SC_NS); } } void p2(void) { while (true) { cout << "p2: " << sc_time_stamp() << endl; wait(0, SC_NS); } } SC_CTOR(DeltaTimeWait) { SC_THREAD(p1); SC_THREAD(p2); } }; There is also one thing I noticed. For example if I change the order of the thread registration in the constructor of the 1st code, and having SC_THREAD(p2) before the SC_THREAD(p1), I get different result. SC_CTOR(Task5_d){ SC_THREAD(p2); SC_THREAD(p1); SC_METHOD(p3); sensitive << evt1; dont_initialize(); } I get the following result: evt1 is activated at 0 s evt1 is activated at 0 s evt1 is activated at 10 ns I am not sure if my reasoning for this result is correct. So I think that we get his output due to reason that at the point where simulation time was 10 ns, we had two choices, we could either schedule p1 or p2 first. Simulation time = 10 ns: Evaluation phase (delta cycle = 0): At this point as I have mentioned earlier, we can either run p1 or p2 first. And in the first case we assumed p2 was run first. But if we assume now p1 will be run 1st instead of p2. So now p1 gets executed and statement evt1.notfiy(5, SC_NS) is encountered. As a result, process p1 gets into the list T and then we sleep the process. Now the process p2 gets scheduled, and the 1st line we encounter is evt1.cancel(), which as result would cancel pending notification evt1.notfiy(5, SC_NS) from process p1. After that evt1.notify() is executed which results p3 getting into R list. So p3 being only in the list R, we execute process p3, and evt1 is notified at simulation of time 10 ns. Question 3: How come that order of thread registration actually affects the order of the process being scheduled? I am not sure if my reasoning is correct, so I would appreciate your feedback, as I am only a beginner in SystemC. Looking forward to your feedback. Ivan.
  17. 1 point
    No. Only assignment (or write() method) triggers update request. Constructor initializes signal value directly. So sig0 constructor generates no events and method1 is not activated.
  18. 1 point
    I went and looked at the website where this stuff was supposed to be and found problems. I then dug around and found an archived copy, did a quick sanity check, and I've now published it on GitHub under github.com/dcblack/SCFTGU_BOOK As noted, I am working on a modern version, but time is limited.
  19. 1 point
    Roman Popov

    sc_spawn and anthoer process

    If you want to pass a parameter to process, then you can use sc_spawn and std::bind to bind parameters.
  20. 1 point
    sc_signal only triggers an event if you write a value different from the current one. If you want to trigger events and hence invoke method/sc_thread you need to use sc_buffer instead of sc_signal. It is a drop-in replacement. Best regards
  21. 1 point
    Yes, SystemC is doing exactly what is supposed to do. Perfect behavior and standard reaction when you don't understand event driven simulators. In Verilog/SystemVerilog, this behavior is called non-blocking assignment (NBA). In VHDL, this is the behavior of a signal.
  22. 1 point
    maehne

    systemc-2.3.2 with C++17

    Hello Sumit, for compiling SystemC using CMake for C++'17, you will have to specify the C++ language standard version through the variable CMAKE_CXX_STANDARD. The value "17" is only supported since CMake 3.8. If you are still using an older version, this might explain your compilation problems. Enable verbose output for your build system to check which flags are effectively passed to your compiler. Passing the C++ standard version via the "-std=c++17" compiler switch ist more fragile when using CMake, as the latter might add conflicting additional flags. Regards, Torsten
  23. 1 point
    David Black

    sytemc temperal decoupling

    Read IEEE 1666-2011 sections 9 & 10. Available for free download from http://www.accellera.org/downloads/ieee. Or watch a free video from https://www.doulos.com/knowhow/systemc/. Or take a class on SystemC & TLM from https://www.doulos.com/content/training/systemc_training.php. TLM 2.0 is a marketable skill and I get many requests for job references. You will need to become proficient at C++, SystemC fundamentals, and then TLM 2.0 in addition to having a good basic knowledge of hardware and software design.
  24. 1 point
    David Black

    approximately timed

    IEEE 1666-2011 section 10.2 states: IEEE 1666-2011 section 10.3.4 states:
  25. 1 point
    HI Can any one provide some example for how to get virtual interface in sequence? I need to use the clk in sequece . Thanks praneeth
×