Jump to content

Leaderboard


Popular Content

Showing content with the highest reputation since 04/07/2019 in Posts

  1. 3 points
    The Accellera SystemC AMS Working Group released the 2020 edition of the SystemC AMS User's Guide. You will find the user's guide on this page: https://www.accellera.org/downloads/standards/systemc This version of the user's guide is fully compatible with the SystemC AMS standard released as IEEE Std. 1666.1-2016. It describes all the features introduced in the SystemC AMS language standard during the last decade. For example, the user’s guide now explains the use of the dynamic timed data flow capabilities, to make AMS system simulations even more efficient and running even faster. The SystemC AMS Working Group is currently preparing the release of the user's guide application examples as separate download. Availability of these application examples will be communicated at a later stage. Please use this forum to post your questions or remarks on the user's guide.
  2. 2 points
    Eyck

    sc_clock Doubt

    sc_clock triggers itself based on the period and the (in your case default) constructor settings. The period is the default_time_unit.
  3. 2 points
    Eyck

    TLM CPU modeling

    There is no such thing as CPU TLM modeling. Usually you write a C/C++ processor model with the needed accuracy (instruction accurate, cycle approximate, cycle accurate) and wrap it in a way that you translate memory accesses into TLM socket accesses. Along with that you need to manage to syncronization of the time of your model and the SystemC time (to run e.g. in loosly timed mode). Another task is to take the returned execution time of the bus accesses into account for the execution of the CPU model. This involves also the selection and implementation of the accesses (DMI & blocking or non-blocking). You can find a complete example of an instruction accurate VP at https://git.minres.com/DVCon2018/RISCV-VP (or https://git.minres.com/VP/RISCV-VP which is a newer version). The wrapper for the C++ model in SystemC can be found at https://git.minres.com/DVCon2018/RISCV-VP/src/branch/develop/riscv.sc/incl/sysc/core_complex.h To put it straight: doing this correctly is a non-trivial task as it is the implementation of a micro-architecture model of a CPU. One option is to build an instruction accurate ISS and add a microarchitecture model like it is done in the ESECS project (https://github.com/MIPS/esesc) BR
  4. 2 points
    You are initailaizing fl_ptr during consturction, not during execution. In generator.hpp you have: float* fl_ptr = reinterpret_cast<float*>(dmi_mem); //ovo sam ja pisao This never updates fl_ptr to the actual value of dmi_ptr. Actually your access should look like: if (dmi_valid) { dmi_mem = dmi.get_dmi_ptr(); //dmi_mem is pointer to ram[] array in memory.h float* fl_ptr = reinterpret_cast<float*>(dmi_mem); for (int i = 0; i != 20; ++i) fl_ptr[i] = 12.7; }
  5. 2 points
    Your sc_trace function is a member function of the TraceList class and cannot be called like the sc_trace functions coming with the SystemC reference implementation. Those are free functions in the sc_core namespace. Moreover your sc_trace implementation is non-static so it cannot be used without a TraceList object. You need to move the function out of the class scope. Basically this is a valid approach to setup complex types. But under performance considerations I would suggest to use a different container. Best choices are std::vector or std::dqueue. And if you are using C++ 11 I would replace the while loop with a range based loop, something like: for(auto& val: var.lst) { // use namespace, compiler otherwise chooses wrong function sc_core::sc_trace(tf, val, nm + std::to_string(pos++)); }
  6. 2 points
    2 days! That's fast response Exactly! If you're not open in the design/pre-release phase you're likely to miss use cases and if the members have committed themselves to solutions and switched their focus to other tasks I imagine that there will be an unwillingness to go back and redo things even if new important insights have been revealed. I think most users would like a code base they can build upon, not one that needs adaptations to make it work. Being fully transparent about the code in the making will reduce the risk for such adaptations What I'm suggesting is free and efficient access to the collective intelligence of the entire community at a point in the development cycles where it makes the most difference. I'm not suggesting a shift in the rights to make the final decisions. That's exclusive to the paying members. What's preventing this from happening within Accellera?
  7. 2 points
    Please be aware, that an sc_and_event_list does not imply that the events in the list are triggered at the same time. I would suggest to keep the only the clock sensitivity and act on the triggers in the body of the method instead: SC_METHOD(func2); sensitive << clk.pos(); dont_initialize(); // ... void func2() { if( nreset.posedge() ) { // nreset went high in this clock cycle // ... } } Alternatively, you can be sensitive to nreset.pos() and check for clk.posedge() (as a consistency check), if you don't have anything else to do in the body of the method. With this approach, you might be able to avoid unnecessary triggers of the method. Side note to Eyck: There's a small typo in the example above, which should should use "&=" to append to an sc_event_and_list. ev_list &= nreset;
  8. 2 points
    Unfortunately I'm not with a member company. I was hoping that I'd have read permissions regardless of my current affiliation. As a user I'd like to see the connection between discussions in the official forum, the issues reported to the issue management system, and the code being developed in response to that. The ability to immediately test that code and possibly give feedback as code comments or a pull request. More like Github, Gitlab and other platforms. Seems to me that this would be a more efficient way to give and get user feedback.
  9. 2 points
    David Black

    Systemc performance

    Perhaps you would like to share your code for measurements via GitHub? Measuring performance can be tricky to say the least. How you compile (compiler, version, SystemC version) and what you measure can really change results. Probably helps to specify your computer's specifications (Processor, RAM, cache, OS version) too. Processor (vendor, version) L1 cache size L2 cache size L3 cache size RAM OS (name, version) Compiler (name, version) Compiler switches (--std, -O) SystemC version SystemC installation switches How time is measured and from what point (e.g. start_of_simulation to end_of_simulation) Memory consumption information if possible This will help to make meaningful statements about the measurements and allow others to reproduce/verify your results. It is also important to understand how these results should be interpreted (taken advantage of) and compared. As with respect to TLM, it will get a lot more challenging. For example, what style of coding: Loosely Timed, Approximately Timed. Are sc_clock's involved?
  10. 2 points
    David Black

    sensitivity list

    You can only specify sensitivity on objects that have events or event finders directly accessible at the time of construction. Normally this means using either a suitable channel, port or explicit event. If you wrap your int's with a channel such as sc_signal<T>, you can do it. Example - https://www.edaplayground.com/x/5vLP
  11. 2 points
    David Black

    Heartbeat, clock and negedge

    You can use it however you like. We didn't use it everywhere and I'm sure there are more areas where it might be applicable. The main point is that "Performance is a function of simulator CPU activity and how well it used." In some cases such as clocks, there is a lot of activity that goes unused. Many designs really only use the positive edge of the clock. In some designs, the activity can even be reduced significantly. Another instance is timers that often are only touched when they are set up and timeout after N clocks. The RTL approach to modeling a timer decrements the timer value on every clock. A behavioral approach would be: void set_timer( int N ) { assert( N > 0 ); delay = N * clock.period(); setup_time = sc_time_stamp(); projected_time = setup_time + delay; timeout_event.notify( delay ); } The current value of the timer can always be had with: int get_timer_value( void ) { return ( projected_time - sc_time_stamp() ) % clock.period() ); } So you really don't even need the clock in many instances. Instead replace clock.period() with a simple constant. Fast and smart SystemC models don't use sc_clock at all.
  12. 2 points
    Actually, you can start a sequence in any phase. It is more important to understand the domain/scheduling relationships between the task based (i.e. runtime) phases. UVM undergoes a number of pre-simulation phases (build, connect, end_of_elaboration, start_of_simulation) that are all implemented with functions. Once those are completed, the task based phases begin. The standard includes two schedules. One is simply the run_phase, which starts executing at time zero and continues until all components have dropped their objections within the run_phase. The other schedule contains twelve phases that execute parallel to the run phase. They are: pre_reset, reset, post_reset, pre_config, config, post_config, pre_main, main, post_main, pre_shutdown, shutdown, and post_shutdown. They execute in sequence. Every component has the opportunity to define or not define tasks to execute these phases. A phase starts only when all components in the previous phase have dropped their objections. A phase continues to execute until all components have dropped their objections in the current phase. Many companies use the run_phase for everything because there are some interesting issues to consider when crossing phase boundaries. In some respects it may be easier to use uvm_barriers for synchronization. Drivers and monitors (things that touch the hardware) are usally run exclusively in the run_phase, but there is nothing to prevent them also having reset_phase, main_phase, etc...
  13. 1 point
    Eyck

    syntax problems

    You can access elements using array index operator like this: in2[0][1]=42.0; But you write you want to put values onto the array. You cannot write onto ports as these are only proxys and do not hold values. You need to create a similar sc_signal array and connect it to the ports. sc_signals hold values so you can put values on them using write(). A side node: you should declare your vectors as: sc_vector<sc_vector<sc_in<float>>> in2{"in2", 4, [](char const* name, size_t idx) -> sc_vector<sc_in<float>>*{ return new sc_vector<sc_in<float>>(name, 4); }}; This names your ports (very helpful when tracing values) and you don't need to call init() separately.
  14. 1 point
    Eyck

    Handling SystemC engine from a Qt5 thread

    Esp. as educational project you should implement it in 2 threads which communicate with each other. Since they run in the same process space you can access data safely once the simulation is in paused state. But you cannot restart the simulation without restarting the process it self. SystemC uses static global variables storing the simulation state and those get only initialized at program start.
  15. 1 point
    sas73

    UVM Library Test Suite and Git Repository

    Hi, I just downloaded the UVM library but I couldn't find any tests verifying its functionality. Are such tests available? Also, is the git repository from which the library was released open? Thanks
  16. 1 point
    @tymonx- Thanks again for the responses, I didn't get a notification about them, otherwise I would have responded a bit faster 🙂 The UVM Packer is not specified as packing bits in any particular format... if the a developer or end user requires a specific format, then they are free to implement their own within the standard. If you've come up with an alternative and you think it'd be useful, please post it! That said, while the format/structure of the bits isn't specified, the LRM is very clear about how packers behave... it seems that the behavior just isn't exactly what you were expecting. I can understand the frustration (FWIW: there's plenty of places wherein the library acts in a way I would consider unexpected, you're not alone there!). The largest disconnect here seems to be with how UVM handles "metadata", ie. data that describes the data contained within the stream. There are 3 basic forms of metadata that Accellera's implementation is concerned with: The current position of pointers in the packer stream (Your magic 8 bytes) The size of a string The validity of an object handle The use of a fixed-size array is an Accellera implementation artifact. It was chosen back in the pre-UVM days, but I believe the basic reasoning for it is that accessing data within a fixed size array tends to be faster than constantly (re)allocating data inside of a dynamic array. The reference implementation does allow the user to easily change the size of the fixed size array, but it will still be a fixed size array. To be clear though, this is an Accellera decision, and you are free to implement a packer which uses a dynamic array instead. Should you choose to make that a queue instead of a dynamic array, then you no longer need pointers for pack/unpack. Your unpack pointer is always 0, your pack pointer is always [$]. Strings can generally be dealt with one of two ways: {size,string} or {string,'\0'}. Accellera goes with the latter, but really either is fine so long as you're consistent. The validity of an object handle is called out by the LRM. The LRM dictates that is_null returns 1 if the next item in the stream is a null object, 0 otherwise. Unfortunately, this is the one place wherein the LRM truly requires _some_ form of metadata being present. You are absolutely free to create a packer which doesn't support this method, but then your packer won't work for 100% of the objects out there. As to your other concerns: The initial values of the member variables is fine because they're 2-state ints, not 4-state integers. They automatically initialize to a value of 0. The library will also automatically flush any packer passed to uvm_object::pack_*, so long as that packer is not actively packing another object (refer to 16.1.3.4 in the 2017 LRM here). Having the pack_* methods use the default packer was another case wherein simplicity/performance was chosen over strict thread safety (again, pre-UVM). I would argue that instead of changing the behavior of "Default/Null packer" to clone, it would be cleaner to simply remove the option altogether. Make it an error to pass null to pack_*, and now the user has to be explicit. No more thread safety concerns (for the library), no more potential for unexpected behavior. Downside? Breaks a _ton_ of existing code, some of which dates back to before UVM existed. The packer is actually one of the more heavily documented features of UVM, even going so far as separating those methods which packer developers need to worry about (16.5.3) from those that the users generally interact with (16.5.4). The fact that the LRM doesn't dictate the format of the bitstream isn't a bug or an omission, it's an intenitonal feature. It's left at the discretion of the developer. The "do one thing, well" philosophy is a bit alive and well: the one thing is that the packer allows you convert a sequence of pack_*/unpack_* calls to/from a bitstream. A quick side story: During the discussions of the packer during the development of the 1800.2 standard, an example was shown wherein all of the methods in 16.5.4 didn't actually modify a bitstream at all, instead they simply pushed/popped their values in separate local queues of bits, bytes, ints, longints, uvm_integral_t, uvm_bitstream_t, and strings. A hook was present which allowed a user to control how that data was eventually packed/unpacked inside of the set/get_packed_state methods. In theory this implementation could be significantly faster, because the packer could choose the optimal layout for each type. This was just an example though, the full source code was not provided. A final note on the fact that the Accellera implementation doesn't exactly match the LRM: You're 100% correct, which is why the release notes include the following: The inconsistency between sections 5.3 and 16.5.3 are being addressed by the IEEE in the next revision. -Justin PS- I get that it's just an example, and therefore I can't tell if protocol_c is meant to extend from uvm_object or not, but you should never call packer.flush in a uvm_object::do_pack call, unless you explicitly created the packer! If the packer has any data in it (including but not limited to metadata), then you just cleared all of that data!
  17. 1 point
    Thanks for the spirited comments @Tymonx! I'll try and respond to all of your messages in one comment, apologies in advance if it's overly long. To the concerns re: the packing of the m_pack_iter and m_unpack_iter into the byte stream, that is a consequence of how the 1800.2 LRM defines the packer's functionality and compatibility. Specifically sections 16.5.3.1 (State assignment) and 16.5.3.2 (State retrieval), which effectively allow one to dump the packer's state, and safely load it into another packer, regardless of what operations have been performed, and in what order, on the original packer. In this way, the state assignment/retrieval methods can be compared to SystemVerilog's process::set/get_randstate methods. They contain enough information to put you in _exactly_ the same state. As an additional aside, it's also important to acknowledge that while uvm_object does provide a pack/do_pack/do_unpack interface, there's zero restrictions on where a packer can actually be used. Users can create/use packers anywhere in their code, not just in the context of a UVM object. As to m_pack_iter and m_unpack_iter being magic numbers, you're absolutely right... but to that end, the entire bit stream dumped by the packer is a magic number. The 1800.2 standard intentionally leaves the formatting of the bitstream to be not just UVM Library dependent, but uvm_packer implementation dependent. This allows for alternative implementations based on performance or other requirements. Additionally, as m_pack/unpack_iter are values of type int, they auto-initialize to 0. For some background on "Why did 1800.2 add the state methods? Why the changes?": Pre-1800.2 it was impossible to use a packer _without_ pushing it through a uvm_object of some kind first, unless you opened up the source code to see how it worked. FWIW: This is precisely what UVM-SystemC did. The 1800.2 standard reversed the polarity though, saying that it's not important that everyone pack/unpack byte streams in the same exact way, but instead it's important that the standard allows for developers to define their own bit packing mechanisms, so long as they all present the same interface to the user. This is also why the various control knobs which altered string and array packing were removed. IOW: If library X wants to pack/unpack with UVM, they don't need to know how Accellera packs/unpacks, they just need to make "class X_packer extends uvm_packer", and follow the rules. So long as they do that, they're safe to use whatever bitpacking mechanism is best for their needs. Your final concerns re: thread safety are valid, but are not constrained to uvm_packer. Unfortunately, the UVM library in general isn't uber-thread-safe, primarily because SystemVerilog isn't particularly thread safe in "zero time" (ie. functions). The same basic singleton flaw surrounds all of the singletons in the library... the default printer, copier, report server... you name it, it's not thread safe. Unfortunately, SystemVerilog doesn't provide any mechanism for "atomic" access to a variable without consuming time. The 1800.2 standard and the Accellera reference implementation do their best to "thread the needle" between general functionality, performance, and strict thread safety (and generally bias in that order). That said, the best place to attack this may be inside of the uvm_coreservice itself... an alternative "thread safer" version could be created that constructed clones of the policies when get_* was called. You'd then have the option of perf. vs (relative) thread safety. I hope that helps to shed some light on the questions, Justin R.
  18. 1 point
    David Black

    How to generate sc_signal at runtime?

    Sc_signals are not data types. Sc_signals are channels, which represent hardware being modeled and are used as mechanisms to transport data between processes. As such, channels are only allowed to be created during the “elaboration phase” that occurs prior to simulation starting up. Also, strictly speaking, sc_port’s are not normal pointers; although, an underlying mechanism uses pointers for efficiencies sake. The operator->() is overloaded on sc_port<IF_TYPE>. You could of course create an sc_vector< sc_signal<T> >, N >, where N was a maximum of the number of signals required and then allocate specific index to each spawned process.
  19. 1 point
    Timur Kelin

    Implement sc_trace for std::string

    The basic idea: calculate hash for the string call sc_trace for the hash value update a translation file which maps hash values and the string contents. Exemplar github project which utilizes this approach: https://github.com/timurkelin/simschd In this project the translation file is written before the simulation starts raw 64-bit hash values: simvision mmap translation applied: simvision mmap is generated automatically and translates string hash (%x=) into string value (-label {}). mmap new -reuse -name schd -radix %x -contents { {%x=0000000000000000 -label { } -bgcolor #000000 -font -*-courier-medium-i-normal--12-* -shape z -textcolor #F8F8FF -linecolor green} {%x=613d30040ed92e78 -label {delay_chain.dly10} -bgcolor #000000 -font -*-courier-medium-i-normal--12-* -shape bus -textcolor #F8F8FF -linecolor green} {%x=d1a020f2dd73715f -label {delay_chain.dly10} -bgcolor #000000 -font -*-courier-medium-i-normal--12-* -shape bus -textcolor #F8F8FF -linecolor green} {%x=69071983ebd1b6d4 -label {delay_chain.dly10} -bgcolor #000000 -font -*-courier-medium-i-normal--12-* -shape bus -textcolor #F8F8FF -linecolor green} {%x=3a5413510c68f021 -label {run_80.exec_80()} -bgcolor #808000 -font -*-courier-medium-i-normal--12-* -shape bus -textcolor #F8F8FF -linecolor green} {%x=55691ef70e86d835 -label {run_60.exec_60()} -bgcolor #8b0000 -font -*-courier-medium-i-normal--12-* -shape bus -textcolor #F8F8FF -linecolor green} {%x=6f9e19f9823cb15c -label {run_40.exec_40()} -bgcolor #4b0082 -font -*-courier-medium-i-normal--12-* -shape bus -textcolor #F8F8FF -linecolor green} } generated gtkwave translation file for the similar appearance 0000000000000000 ?grey0? 613d30040ed92e78 ?grey0?delay_chain.dly10 d1a020f2dd73715f ?grey0?delay_chain.dly10 69071983ebd1b6d4 ?grey0?delay_chain.dly10 3a5413510c68f021 ?OliveDrab?run_80.exec_80() 55691ef70e86d835 ?DarkRed?run_60.exec_60() 6f9e19f9823cb15c ?navy blue?run_40.exec_40()
  20. 1 point
    This compiler warning is a false positive. There is a loop in sc_fifo<T>::read(T&) ensuring that the fifo is not empty (and the success of the nb_read(T&) is even guarded by an sc_assert😞 while( num_available() == 0 ) { sc_core::wait( m_data_written_event ); } bool read_success = sc_fifo<T>::nb_read(val_); sc_assert( read_success ); The check for num_available() is even stricter than the check in buf_read, but I can imagine that some compilers might not be able to prove this invariant. Therefore, unconditionally initializing the local variable to silence the warning might be an acceptable trade-off.
  21. 1 point
    Since you are talking about timing I would stick to a more AT like modeling style using the non-blocking transport functions. In this case you should use a memory manager (see section 14.5 of the IEEE standard). For this you need to implement the tlm::tlm_mm_interface (there a few implementations out there, you may google them). The mechanism works similar to a C++ shared pointer. The initiator always pulls a new transaction from the memeory manager and sends via its socket. Each component dealing with the transaction calls acquire() on the payload and release() once it is finished with it. Upon the last release() call the transaction is automatically returned to the memory manager and can be reused. HTH
  22. 1 point
    SiGa

    sc_fifo.read() does not work

    SC_MODULE(DF_Fork){ sc_fifo_in<int> input; sc_fifo_out<int> output1,output2; void process(){ while(1){ int value = input.read(); output1.write(value); //output1.write(value); output2.write(value); } } SC_CTOR(DF_Fork) {SC_THREAD(process);} }; You never write on output2. Your printer then remains at value = input.read(); since it waits till data is available. Thus the simulation has nothing to do and stops itself. You can read about sc_fifo methods here: http://www.asic-world.com/systemc/channels4.html
  23. 1 point
    I have to correct my statements. It works they way I described it, I unintentionally looked at the wrong trace signals...
  24. 1 point
    This is correct, you cannot trace dynamic data structure. This is not even a SystemC limitation, but limitation of VCD waveform dump in general. VCD does not allow to add/remove signals to waveform dynamically. So usually you have two options : 1) If maximum capacity is known in advance and is small, you can create your own "list" that utilizes statically sized array as a storage: template<typename T> struct my_list_item { bool has_value = false; T value; } template<typename T, size_t MAX_SIZE> class my_list { std::array<my_list_item, MAX_SIZE> storage; // ... } 2) If maximum size is large or unknown, but it is sufficient for you to trace only head and tail of the list, you can have a copy of tail and head that is updated on every push and pop: class my_list { std::list<T> storage; my_list_item head_copy; my_list_item tail_copy; //... custom push pop }
  25. 1 point
    Looks like XY problem to me. If you need pointer to event, use pointer.
  26. 1 point
    Roman Popov

    sc_fifo data_read_event

    Did you probably forget to add wait() into consumer thread to suspend it after first read?
  27. 1 point
    Roman Popov

    sequence processing

    SystemC standard does not guarantee any order of process evaluation within a single delta cycle. So in first example both 2,4 and 4,2 will be correct.
  28. 1 point
    e.notify(); // immediate notification is executed "immediately" - Thread2 added to set of runnable processes e.notify(3,SC_NS); // e added to kernel event queue, it will be triggered in 3 ns e.notify(3,SC_NS); // e added to kernel event queue to be triggered in 3 ns e.notify(); // previous notification canceled, and instead event is notified immediately, Thread2 added to set of runnable processes
  29. 1 point
    Setting library path != Linking library. Also add -l systemc to g++ options.
  30. 1 point
    Eyck

    Bus width of socket

    Again, in your case you model a burst read which means in reality data gets transfered in several beats (32 in your case). Since your model does not deal with timing you wont notice that, all you see is that your data gets transfered. Look, TLM2.0 implements a generic bus protocol. Most of the real-world protocols have a so called burst transfer (e.g. checkout the AMBA specs). So the way to model this in an abstract way is to have a bust with and the amount of bytes being transfered in on bus transaction not in one beat. This way it is also possible to describe byte and half-word transfers. HTH
  31. 1 point
    Eyck

    Generic pointer to sc_out<T>

    boost::variant would be an option or you use a union. In the latter case you loose the type safety...
  32. 1 point
    Eyck

    Generic pointer to sc_out<T>

    Well, this topic is not easy to solve. In C++ each template instantiation (like sc_in<bool>) is a separate class in the class hierachy. The common base class is sc_port_base and this is in this context more or less useless. Actually there I see 2 options: You store a sc_port_base pointer in your map and upon each write you check for the typeid of the specific template instance and down-cast it using dynamic_cast. This is inflexible and needs additional coding if you want to use new type. You store a writer function in your map which knows how to translate a generic value (like int or double) to the particular value. This might by a lambda which captures the port reference and therefore 'knows' hwo to write to this port. But in this case you would loose type safety as you have to store a generic function unless you can use std::variant. So your map would have to be declared as typedef std::map<std::string, std::function<void(unsigned)> Map0 or (C++17): typedef std::map<std::string, std::function<void(std::variant<bool, sc_dt::sc_uint<2>>> Map0 I personally would go for option 2 as it is simpler and more flexible... HTH
  33. 1 point
    You have controversial requirements: a) put stored value when enable == 1 , which sounds like a dff with output_enable b) put input to output when enable == 1, which sounds more like a latch Anyway, in both cases you will need to make process sensitive to enable signal. And usually such low-level logic is modeled with SC_METHODs. In SystemC context "register" usually means some memory-mapped CSR on TLM bus 🙂
  34. 1 point
    The Accellera UVM Working Group has released the UVM 2017 0.9 reference implementation. This implementation is available as a SystemVerilog class library and is fully compatible with the IEEE 1800.2-2017 standard as defined in the Language Reference Manual. The library can be downloaded for free here. The IEEE 1800.2-2017 standard is available free of charge from the IEEE Get program, courtesy of Accellera. We encourage you to use this forum to provide feedback, ask questions, and engage in discussions.
  35. 1 point
    There are several ways to do this: you might use a different way to carry signals which are more TLM like. One option would be to use tlm_signal. The other common option is if your CPU writes into the register of your interrupt controller via TLM it carries the delay which is essentially the offset of the CPU local time to the SystemC kernel time. If you here just break the quantum and call a wait() so that the SystemC kernel can sync up and the signal change propagates you should be fine.
  36. 1 point
    Vegh, Janos

    Systemc performance

    I'll surely do, but this was the first verified (by me) measurement. And, I wanted to know if it can be interesting for this audience. I will clean up the code and upload in the coming days. Although the absolute values of the data are not so meaningful, even I did the measurements in debug mode.
  37. 1 point
    Eyck

    timer with systemC

    If you run a simulation until a certain point it time the kernel stops before evaluating the processes at this time point. So if you schedule an event for lets say 100ns and simulate for 100ns then the process being sensitive to this event will not be executed (yet). So this is intended behavior. BR
  38. 1 point
    Eyck

    using clocks in tlm

    Adding to Davids answer: you can supply clocks to the modules having initiator and/or target sockets. This is can be done using the usual signal/sc_in/sc_out means as David mentioned. There is also the option to have 'tick-less' clock as David presented many years ago (http://www.nascug.org/events/12th/nascug12_david_black.pdf). This can also be achieved by distributing a signal just carrying the clock period as sc_time and caculating the time points in the modules. This way it is even possible to model timers or PWM (e.g. https://git.minres.com/DBT-RISE/DBT-RISE-RISCV/src/branch/develop/platform/incl/sysc/SiFive/pwm.h). This modelling style avoids the many context switches implied by toggling clocks. All this holds true for LT and PV modelling, if you think about AT modelling the story becomes different. But this is as usual: you trade speed for accuracy. BR
  39. 1 point
    David Black

    using clocks in tlm

    Yes, you can supply clocks to TLM, but this is a very bad idea in general. Clocks will slow down your simulations There are many ways to insert clocks: ports, local instances, global references. The best b_transport implementations find ways to avoid calling wait. More precisely, we attempt to reduce context switching to a minimum and its associated overhead.
  40. 1 point
    David Black

    Timing in TLM

    @Eyck I would point out that Timing Annotation is not limited to Loosely-Timed (LT) modeling, but can also be applied to Approximately-Timed (AT) models (see section 11.1 of IEEE-1666-2011); however, there is an important difference. LT timing annotation describes temporal decoupling as you explained. AT timing annotation is a way of indicating where a phase applies. This has some odd implications that are not immediately obvious. For instance, I can start an nb_transport_fw transaction with a non-zero annotated delay: tlm_phase phase { BEGIN_REQ }; sc_time time { 50_ns }; auto status = nb_transport_fw( payload, phase, time ); ///< begin transaction 50 ns in the future // Note that ns_transport_fw may increase the time (same as b_transport); however, it may not decrease the time. Section 11.1.3.1 describes this in detail. Why would this be done? Perhaps the initiator knows wants to dispatch a transaction and doesn't want to wait around to its initiation. I cannot immediately think of why the returned value might change, but it is legal. The main rule about time in SystemC requires that time never goes backward. No playing Dr. Who.
  41. 1 point
    Eyck

    Timing in TLM

    All of these relate to the concept of loosly-timed simulation. The basic principle behind this is that parts of the design can simulate larger time slices without returning control to the simulation kernel; the run ahead of the rest of the simulation. This is used e.g. for processors and alike as for quite some parts the do not interact with the rest of the design and create (a memory read does not really trigger any action other than returning some data). This way the simulation speed and hence the simulation performance can be drasticalliy improved but you trade performance for accuracy. This domain (or part of the simulation) running ahead of the simulation kernel is temporally decoupled. As such it needs some mechanism to control its local time (the amount it is ahead of the simulation kernel). This is done by the quantum keeper, the quantum is the amount of time the decoupled domain is allowd to be ahead at max. To allow interaction with the rest of the design all interaction need to carry some information what the local time in the dcoupled domain is, this is called timing annotation. This information is needed to either schedule events in the simulation kernel to happen at the correct time or to decide to break the quantum which means the decoupled domain is stopped and control is returned to the simulation kern until it reaches the local time of the decoupled domain, they are in sync then. HTH
  42. 1 point
    Eyck

    why is,what is, and how is tlm used ?

    Well, in TLM1.0 there is even a tlm::tlm_fifo channel which provides something similar what you use. The sockets defined in TLM2.0 are more geared towards memory-mapped busses and provide facilities to model for speed (DMI, loosly-timed blocking interfaces) or accurracy (approximately-timed non-blocking interfaces). To achive this with pure SystemC provided classes takes some effort and it ends to be proprietary... BR -Eyck
  43. 1 point
    From SystemC standard: SystemC requires that you add sc_module_name as a parameter to module constructors, like this: MULT(sc_module_name, int var_a, int var_b); MULT(sc_module_name); This is a hack that allows SystemC kernel to track lifetime of constructor.
  44. 1 point
    sas73

    UVM Library Test Suite and Git Repository

    @David Black I did stumble upon an accellera/uvm repository on GitHub. Seems to be what I was looking for although it has been dead since UVM 1.2. Why have it there and not use that platform?
  45. 1 point
    sas73

    UVM Library Test Suite and Git Repository

    Thanks David. It sounds like no such tests are available. Open source projects in general are not always good at providing their test suites but I find it a bit odd that on open source library for verification doesn't provide the test suites showing how the library itself is verified. It would be easier for people to suggest improvements if they can verify whether or not such a modification breaks something else.
  46. 1 point
    Hi. This is because an unbound port cannot be read. A port forwards all read and write calls to the actual interface (signal) it is bound to. In you module constructor, you are still in the model set up and elaboration phase. The port is not yet bound to any signal. Hence, you cannot read from it. Accessing ports should not be done befor end-of-elaboration. Greetings Ralph
  47. 1 point
    SystemC TLM is a part of the SystemC standard (both parts TLM1 and TLM2). True, it is an newer addition, but it is never-the-less part of the standard. TLM1 was the first attempt to standardize an API, which worked, but it didn't address the needs of the SystemC community as well as had been hoped. TLM2 standardizes a methodology to model address mapped bus communications and the associated API. It allows for easier exchange of IP blocks for simulation. TLM emphasizes that "ports" are not just wiring connection points, but rather a nexus for higher levels of communication. TLM2 has "sockets", which are really just glorified SystemC port combinations (sc_port & sc_export). TLM2 also standardizes some concepts (even if not stringently) of different styles of transaction level modeling (sometimes called coding styles). For instance, "loosely-timed" (LT) represents "execute as fast as possible while maintaining register functional accuracy"; whereas, "approximately-timed" (AT) means "provide sufficient timing detail to allow bus-level timing analysis[1]". AT does not simulate as quickly as LT because it has to provide extra details and timing behavior. Note 1: Not necessarily the same as clock cycle accuracy. On the other hand, the SystemC core provides the fundamental mechanisms that allow for design encapsulation (sc_module), event-driven simulation (sc_event and wait()), processes (SC_THREAD, SC_METHOD), a notion of simulated time (sc_time) and channels (sc_interface, sc_prim_channel, sc_channel). Channels are one of the most important features and enable abstraction of safe interprocess communications. SystemC also provides the minor addition of hardware datatypes (sc_logic<>, sc_int<>, sc_fixed<>, etc). It also provides primitive communications channels such as sc_signal<> and sc_fifo<>. Thus, the SystemC core provides the foundation needed to implement TLM. Sadly in some sense, SystemC provides a number of simplifications for writing RTL even though it is fundamentally not the strong point of the simulator. To some degree these simplifications are an holdover from SystemC 1.0 for backwards compatibility. I said sad because the simplifications have encouraged many to think of SystemC as an appropriate vehicle for writing RTL code, but then get frustrated at the lack of performance (for RTL). SystemVerilog and VHDL are much better suited for that task. The RTL aspect of SystemC is good in making it easier to interface SystemC to the other languages for co-simulation.
  48. 1 point
    Hi. The never ending wait may be caused by race conditions. a) Notify with no argument means immediate notification. I.e., all processes sensitive to this event are made runnable in the same delta cycle. This may lead to non-deterministic behavior and should be used with care. Notify means all processes sensitive to this event are made runnable. The process in your case is sensitive to the event when its execution reaches the wait instruction. When the notify instruction is executed before the wait instruction is reached, no process is sensitive to the event. Event notifications are not stored for later waits. Assume the following example: p1(){ wait(ev1); cout << "wait done"; } p2(){ ev1.notify(); } When p1 starts first, it executes until wait is reached. Then p1 is suspended and p2 continues. The notification of ev1 is executed, p1 is made runnable again, and the message is printed. When p2 starts first, the notification of ev1 is done without any process waiting. Hence, it has no effect. Then p1 is started. It reaches the wait statement and will wait forever because the event notification has been executed before. No message will occur. Since SystemC contains no guaranty about the order in which processes runnable in the same delta cycle are executed, a model like the example leads to non-deterministic behavior. Greetings Ralph
  49. 1 point
    apfitch

    user defined data type signal assignment

    How do you know the assignment is not working? When are you printing out the assigned value? Remember that you must wait at least a delta for a primitive channel to update. There's more about user defined types and sc_signal here http://www.doulos.com/knowhow/systemc/faq/#q1 regards Alan
  50. 1 point
    Admin

    Welcome!

    Welcome to the Accellera Systems Initiative forums. Please register to start new topics or reply to existing topics. We have resently migrated our UVM forums from UVMWorld to this site. If you were registered on the previous UVM forum site, you should be able to log into the forums using your username and password from the UVMWorld forums. If you had an account on both the UVMWorld forums and the Accellera forums and these accounts used the same email address, then log in with the username and password of the forums.accellera.org account, not your UVMWorld account. If you do not remember your password, you may reset it. If you have any questions about using the forums, click the Help button at the bottom of any forum page. If you need any help with your account and you are logged into the site, click the Messenger icon (a letter) in the upper right of your screen, click Compose New, enter “admin” in the Recipient’s Name field, compose your message, and then click Send. You may also send an email to admin@lists.accellera.org. Thank you, Accellera Systems Initiative
×
×
  • Create New...