Jump to content

Eyck

Members
  • Content Count

    41
  • Joined

  • Last visited

  • Days Won

    10

Everything posted by Eyck

  1. Actually, I forgot to answer your quesions, so here we go. Can struct contain signals that flow in different directions? Yes, of course. struct is just a a wrapper which handles datatype as one Can sc_inout<struct T> also map directly to another module with the same sc_inout<struct T>? Well, ports need to connect to signals, there is no way to connect 2 ports directly except you do a hierarchical binding Am I also setting the struct contents correctly? This I answer in the last post.
  2. The problem is that you do not write to the signal carrying the struct (and therefore you do not trigger any event). The SetValid() call implicitly triggers a read (thru the overloaded cast) but you never write back to the signal. Either you change the use of SetValid (and SetReady): { hs data = handshake.read(); SetValid(hs, false); handshake.write(data); } Here the call to wriite() trigges the respective events. The other option is to change SetValid() to take a signal reference and move the code into the function. Best regards
  3. Well, the answer is i bit more complex. The main difference is that the standart requires that during the nb_transport call no sc_wait is allowed while in b_transport it si allowed. So any implementation adhereing to the standart guarantees this. Let's first look at the non-blockig implementation. tlm_phase do not denote a phase directly rather time -points o the protocol. Actually you have to phases: request and response which are denote by 2 time points each. So the initiator can indicate a start or end of a phase of a transaction and be sure that the call is not blocked by a call to wait(). So you can model the behavior and timing of a bus transaction in a fairly granular way and do something while the transaction is on-going. You can even have 2 transactions in parallel, one being in the request while the other one is in the response phase (or even more if you have more phases defined). The transaction are pipelined. Looking at the b_transport situation is different. The target can delay the transaction by calling wait() until it is ready to respond. During that time no other transaction can be ongoing, the initiator is blocked and cannot react to it. Blocking accesses can be used if timing of the communication is not of interest/not modeled (the other scenarion is loosly timed models, but that's a different story). They are easy to implement and easy to use. Non-blocking is used if the timing of the communication needs to be modeled in more detail. E.g. this allows to model, simulate and analyse bus contention situations as it allows to attach timing to all phases of a bus transaction lile grant, address phase, data phase. I hope this sheds some light -Eyck
  4. 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
  5. 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
  6. Actually you could use some kind of a router or broadcaster between the master and the target(s). Examples of this can be found here: or here: https://git.minres.com/SystemC/SystemC-Components/src/branch/master/incl/scc/router.h where the first one may be better suited as a stand-alone example HTH
  7. Eyck

    event vs software call

    SystemC is an event based simulator as VHDL or (System)Verilog simulators are. So you would write to signals, the update their values and notify an event for that so that processes can react on them. This is described in the SystemC standard, I guess paragraph 4.2 Simulation. The downside of this that each event and the evaluation of processes being triggered by this takes time. As the processes are often fairly short this incures a significant overhead and speed impact. In TL modeling you forward the function calls via a port/export directly to the affected/addressed module/function. This way a lot of context switches can be avoided and the simulation speed is higher. But since the effect (e.g. writing a register) happens immediately care needs to be taken to not introduce feedback loops and a like which won't happen if you use signales and events. To model timing you also carry some delay time with the transaction so that the functions along the call chain and the target function can tell the initiator of the transaction how long the entire transaction took. Best is to have a look into the examples coming with TLM2.0 (now being part of the SystemC distribution), also Doulos has some explanation and examples: https://www.doulos.com/knowhow/systemc/tlm2/ Best regards
  8. Eyck

    The conceptual behavior of sc_in<>

    In the case Roman described you need to declare InputChanged as SC_METHOD. Otherwise your simulation time won't progress. If you want/need to stick with SC_THREAD you would want to write something: void XXX::InputChanged() { while (1) { wait(); // wait for the events in the sensitivity list. For explicit wait use wait(Address.default_event()) cerr << '@' << sc_time_stamp() << ' ' << Address<< endl; } } Best regards
  9. Eyck

    Build error with 2.3.2

    It seems you did not rebuild entirely your design. The symbol sc_core::sc_api_version_2_3_2* ist there to make sure your object files are build against the right systemc library and its headers. In general they are not binary (ABI) compatible between versions. Just switching the link libraries is not enough, you need to do a 'make clean' or whatever you need to tun to remove all build artifacts of your model and rebuild the entire stuff. HTH
  10. The time resolution is the minimal time step the simulater can advance, not how it is formatted or printed. Internally time is represented as in integer value which you multiply with the time resolution to get the actual time. And BTW, a delta cylce has by definition not time associated. If you want to format the time appropriately you would want to get this internal time value (sc_time_stamp().value()) and format it accordingly based on the time resolution. Another way would be to use to_seconds() (which returns a double) multiply it with 1000 and fomat it accordingly using the io manipulators std::cout << std::setprecision(2) << sc_time_stamp().to_seconds()*1000. << " ms" or the respective printf format string. Best regards
  11. Actually this is not going to work as it is quite unlikely that both events fire at the same delta cycle. So you would write something like void do_dff(){ if(enable.read()) q=d; } sc_ctor(){ SC_METHOD(do_dff); sensitive << clk; } The only option to concatenate events is to use sc_core::sc_event_and_list and sc_core::sc_event_or_list but those can only use in dynamic sensitivity (wait() for SC_THREADs and next_trigger() for SC_METHODs). Best
  12. Eyck

    SystemC code running with testbench

    Well, there are several problems in your code: naming and sc_out input is counterintuitive - but this is minor you use a limited range integer and assign values outside this range. sc_in<2> is a 2.bit integer and can hold values from -2 to 1. it seems you did not understand and obey event scheduling, more see below So what you see in line 16-22 of the output is the initial invocation of tb::source(), tb::sink(), and statem::controller(). There tb::source() writes 11 to input_sig and statem::controller() write enable=false. Due to the write to input_sig tb::source(), tb::sink(), and statem::controller() get invoked again (the are sensitive to the value_changed event) as the output line 23-29 show. tb::sink() now writes the same value to input_sig again but this does not trigger any value_changed event. Since no process is sensitive to enable and no other events are left over the simulation kernel stops the simulation. As there is now wait statement in your model you do not see any time advancing, everything happens at time 0 (but in different delta cycles). To my experience you should use SC_THREAD when you have an active component (tb in your case), here you can easily implement an implicit statemachine and advance time. Since SC_METHODs are not allowed to block (call wait()) they are more suited to reacting components. If you describe the intention I can provide you an example on how to do this. Best regards -Eyck
  13. Eyck

    A void value confusion

    Well, actually the error message from the point of the compiler is quite right: using the '*'-operator you intent to dereference the return value of write() which is 'void'. BR
  14. Eyck

    SystemC linking problem in Ubuntu

    I agree here with David, best would be to share the basic parts of your code as well as the complete commands and outputs From your description you have your DUT and your testbench in a separate file. You should compile them (inlcuding your main.cpp) into .o files e.g. by running something like g++ -I. -I$SYSTEMC_HOME/include -L. -L$SYSTEMC_HOME/lib-linux64 -c <cpp file here> and then link all .o file into your executable like: g++ -L$SYSTEMC_HOME/lib-linux64 -Wl,-rpath=§SYSTEMC_HOME/lib-linux64 -o main *.o -lsystemc -lm This is a basic C++ compile flow, see also here https://www.cprogramming.com/compilingandlinking.html or here: https://www3.ntu.edu.sg/home/ehchua/programming/cpp/gcc_make.html BR
  15. 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
  16. 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
  17. Eyck

    Non Constructible but Copyable !

    Hi Sumit, Quoting http://en.cppreference.com: Some member functions are special: under certain circumstances they are defined by the compiler even if not defined by the user. They are: Default constructor Copy constructor Move constructor (since C++11) Copy assignment operator Move assignment operator (since C++11) Destructor So in the code you show you just delete the default constructor and the destructor. Obviously this does not make sense as you cannot construct any object since you do not have a parameterized constructor. But if you have one this declaration makes sense: the user of this class cannot create a default object, he has to provide some parameters. Deleting the destructor prohibits the creation of an object on the stack, you can only create them on the heap (and never release the memory except you use placement new on a pre-allocated area). But the the standard comittee has a special section on this in the C++ core Guidelines: C.21: If you define or =delete any default operation, define or =delete them all BTW, if you inherit from a class having a deleted destructor the destructor of the child is also deleted HTH -Eyck
  18. Eyck

    VCD dump with Hierarchy systemc-2.3.2

    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
  19. Eyck

    Implement sc_trace for std::string

    Actually Sumit is right, you need to convert the string to a bit vector (sc_bv) of length string.lenght()*8. And here the problem starts: the sc_bv needs to have a constant lenght from the very beginning on and it cannot change during the simulation as the length is store in VCD at the very beginning of the file. In the viewing tool you can then select an interpretation of the bit vector to see a string. Best regards Eyck
  20. 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. 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.
  22. You might have a look at https://github.com/Minres/SystemC-Components/blob/master/incl/scc/router.h. This one uses mixins to enhance the functionality of tlm::tlm_initiator_socket/tlm::tlm_target_socket but basically implementes what you are describing. An example how to use it can be found here: https://github.com/Minres/SystemC-Components-Test/blob/master/examples/simple_system/simple_system.cpp Best regards
  23. Eyck

    beginner problems on fifo waveform

    Hi, you cannot bind interface to e.g. a class implementing those interface. What you can bind are sc_port and sc_export. So you would need to change your declaration to sc_core::sc_port< sc_core::sc_fifo_out<int> > output1; sc_core::sc_port< sc_core::sc_fifo_in<int> > input1; But this is not going to solve your problem as you cannot trace an sc_core::sc_fifo_out interface. Tracing is only possible for elements having a value semantic which are variables of various types (primitive ones like int or composed ones coming with the SystemC library like sc_int or sc_bv) and signals (since they have also a value semantic). interfaces (like are sc_core::sc_fifo_in) are essentially description how to manipulate things and therefore not trace with a tracefile. Using SCV it would be possible to do so but requires implementing some glue code. BR
  24. Eyck

    clock generation in system c

    The clock cycle is determined by the wait(1, SC_NS) statements withing the for loop. This defines the duration of the high and low phase of the clock you are seeing. The timesacel message comes from the VCD trace file (more specifically its writer) saying that the recording resolution will be teh default of 1ps which might be too small for some cases. You may ignore this message or explicitly set the VCD timescale. What Ameya is refering to is to replace the explicit clock generation with the SystemCs own sc_clock. This would alleviate you from describing the clock changes explicitly. Actually in my opinion this is a really bad example for several reasons: it bloats the sc_main function with testbench coder it mixes periodic signal change generation (the for loops) with functional code (writing reset and enable) it does not use SystemC utilities which make coding easier Best regards
  25. Hi, it seems you lack a basic understanding of C/C++ visibility of variables. As fifog32 is declared a local variable in sc_main you can only access it in sc_main, it is unknow in any other function. BR
×