Jump to content


  • Content Count

  • Joined

  • Last visited

  • Days Won


Everything posted by Eyck

  1. Well, without lnowing the implementation it is hard to tell. I suppose your initiator sockets are connected to target sockets at he bus and the initiator sockets of the bus are connected to the target sockets of your target components. All these sockets need to be bound to each other (by calling bind() or the operator() function). There is no concept of bind-by-name in SystemC. Maybe you should have a look here: https://www.doulos.com/knowhow/systemc/tlm2/tutorial__3/ Sockets need to be bound except they are declared with the appropriate binding policy (the 4th template of the sockets). If this is not the case you need to create dummy targets.
  2. In principle yes, but I would not call it LT or AT as it depends on hte use of a memory manager which can be used in any case. Cheers
  3. Actually this is done in the desrtuctor of the tlm_generic_payload. This part calls for all extensions the free() function. So if out is handled properly destroyed all extensions are destroyed as well. The other option is to call free_all_extensions() explicitly which also calls free() for all extensions as well as for auto extensions (those might be registered when a memory manager for the generic payload is used, usually in AT style modelling using the non-blocking interfaces). HTH
  4. Eyck

    sc_uint and unsigned int

    unsigned int has always the length defined by the underlying platform while sc_uint<> lets you specify the exact bit with of the type. In your case case I would use 'unsigned int' as it is faster and has less overhead. Best regards
  5. Actually your code, its behavior and the spec is in sync. You do not have hierarchical binding as you bind an initiator to a target socket. Therfore you need to register at least one of the callbacks so that the interface get bound to the target socket. Best regards
  6. This means that a port is not bound to an interface. A port is just a kind of a forwarder of an interface. So if none is bound nothing can be forwarded. E.g. if you have a sc_in<bool> it forwards the sc_signal_in_if which allows you to read and wait for events. But there needs to be 'something on the other side' which is usually a signal (implementing the sc_signal_in_if) being bound to the socker. But without further information it is hard to provide more help. Best regards
  7. Well, I don't know how your infrastructure looks like, but in general your setup is ok. What is missing is to set the streaming width which should be one in your case. So a bit more context would be allow to help you better. Context means: how are the sockets connected (is there a direct connection initiator->target or do you use some bus system) how do you read the value out of the payload? Best regards
  8. You need to register callbacks to them so that they are bound to an interface. See Unbound multi_passthrough_initiator_socket/multi_passthrough_target_socket In general I would discourage the use of them (or at least suggest to carefully think about their use) as they have several drawbacks: you cannot bind a target socket to a multi_passthrough_target_socket and you cannot bind in before_end_of_elaboration (see also Is there any order requirement for binding multi_passthrough_initiator_sockets?). BR
  9. Eyck

    Checking ports for power estimations

    Well this a little bit about data representation. old_data is a pointer to a uint8_t and this is what you see in the variables view. It has the value of 0x7ff..fdb10. The memory at this address is 2 which is the lowest byte of the first element in your struct (x of type int). Actually using the struct the compiler orders the 2 elements in a row. Depending on the platform and the compiler the members might be 32 or 64 bit long. Lets assume the int is 32bit and the long is 64 (gcc on 64bit Linux). The layout is as follows (the suffix denote the byte number): old_data -> x.0 x.1 x.2 x.3 y.0 y.1 y.2 y.3 y.4 y.5 y.6 y.7 So the value 2 is the lowest byte of the old_val.x variable having the value of 2 (or 258,...) Well, the struct shown above is not entirely correct. The compiler might choose to put padding bytes inbetweeen the members for performance reasons. In this case above there will be 4 byte of padding between x and y so that y is at an aligned address (a multiple of 8). So you would declare it as struct __attribute__ ((__packed__)) my_data { int x; long y; }; to avoid the paddng. See also https://gcc.gnu.org/onlinedocs/gcc/Common-Type-Attributes.html#Common-Type-Attributes Back to your question: you use the pointer like in an array. the notion *(old_data+i) is equivalent to old_data[i] So in the for loop you iterate over every byte belonging to the struct. BR
  10. This message indicates that you link 2 libraries or object files into one executable which are build against 2 different versions/configurations of the SystemC library. Actually this (or a similar) symbol created during the build of libsystemc and part of the libsystemc. It ensures that the header configuration and the compiled library match. It does not relate to TLM at all. One reason could be an inconsistence wrt the use of C++11, see here: https://stackoverflow.com/questions/46875731/setting-up-a-systemc-project-with-cmake-undefined-reference-to-sc-core Best regards
  11. Eyck

    Checking ports for power estimations

    I'm not sure if I get your first question right. Essentially this is a C++ question. But what you could do is a type erase of your (POD) data, use it as a byte array and count the changed bits using XOR (be carefull to you plain data, no classes). Something like: struct my_data { int x; long y; }; my_data old_val, new_val; uint8_t* old_data = reinterpret_cast<uint8_t*>(&old_val); uint8_t* new_data = reinterpret_cast<uint8_t*>(&new_val); unsigned toggles=0; for(size_t i=0; i<sizeof(my_data); ++i){ uint8_t diff = *(old_data+i)^*(new_data+i); uint8_t mask=1; for(size_t j=0; j<8; ++j, mask<<=1) if(mask&diff) ++toggles; } Regarding your second question: you transport the data via a signal which implements the signal_in_if. This interface has a value_changed_event() getter which returns an event firing when the value of the signal changes. Just wait for this event.
  12. What you can do is build your driver software as a shared library with a main function. In a SC_THREAD you just load the library and execute the main function. Along with this you have to implement a few utility functions (read, write, wait) which interact with the SystemC kernel or your DUT and being used by the main function (and the called functions from there). This is called host based or host compiled simulation (you may check the search engine of your choice for it). With some infrastructure it is even possible to mimic interrupt. Another option is to use some instruction set simulator (e.g. QEMU, DBT-RISE-RISCV, or some commercial alternatives) and do you driver development using a virtual prototype... Best regards
  13. There is no predefined way. You would have to have No_OF_SUBMODULES sc_signal<bool> connecting to the sc_out<bool>, one sc_signal<sc_dt::sc_uint<No_OF_SUBMODULES>> connecting to the sc_in<..>, and a SC_METHOD. The method needs to be sensitive to the bool signals, assemble the sc_uint and write it to the sc_uint signal. HTH
  14. See the answer to your other post. In a few words it describes the duration of the phase and saves a second call just to mark the end of the phase. Best regards
  15. The 10ns tells the initiator that the request phase (or address phase in some bus protocols) takes 10ns. During 110ns and 150ns simulation time the target executes the read. The 5ns in the BEGIN_RESP/END_RESP tells the target that the data/status transfer over the bus (the data phase on some bus protocols) takes 5ns. The annotated times in the return path is to save a second function call (END_REQ and END_RESP respectively) at two more simulation time points (120ns and 155ns). This way you can increase the performance of the simulation. Best regards
  16. BEGIN_REQ/END_REQ and BEGIN_RESP/END_RESP mark time points in the protocol. So in the stanndard implementation you have 2 phases: request and response. Depending on the type of access various data is been transferred: for a read REQ usually carries the addr while RESP carries the data and status while during a write REQ carries addess and data while RESP just carries the status. It is up to the initiator and target to care for consistency of the data in the payload, in most implementations I''ve seen the data is sampled/set at the BEGIN_* time point. Best regards
  17. As you might know TLM2.0 defines forward and backward interfaces. Those have default implementations in the simple initiator/target sockets. They are fine for many case (e.g. get_direct_mem_ptr() denies DMI) but if you need to change/customize the behavior you can register appropriate functions here. Best regards
  18. Just looked further: there is a typo in case 1. It should read //bind for(int i=0;i<3;i++){ objA->initiator_socket[i]->bind(*(objB->target_socket[i])); } as you use an array of pointers. Again, sc_vector eases your life: //Model A sc_core::sc_vector<tlm_utils::simple_initiator_socket_tagged<ModelA>> initiator_socket; ... // Model B sc_core::sc_vector<tlm_utils::simple_target_socket_tagged<ModelB>> target_socket; ... //bind for(int i=0;i<3;i++){ objA->initiator_socket[i].bind(objB->target_socket[i]); } The same applies to case 2: //bind objA->initiator_socket1->bind(*(objB->target_socket2)); objA->initiator_socket2->bind(*(objB->target_socket3)); objA->initiator_socket3->bind(*(objB->target_socket1)); Best regards
  19. In case 1 you should use sc_core::sc_vector<..> instead of a plain array as you cannot call constructors for plain arrays (what sc_vector does). Given that objA and objB are pointers case 1 is ok and works also with the sc_vector. Case 2 is fine as far as I see... Best regards
  20. Eyck

    Drive SCModel from a C-Shell

    Actually you don't assign anything to adata->sdata in sc_main In your if branch testing the pointer for NULL and create the design but then you throw away the pointer. So it is called a second time after calling sc_start() and it is not allowed to instantiate primitive channels after the elaboration phase. But in genereral your approach is quite a mess and prone to errors (as you encountered already). Why don't you put your outer for-loop in sc_main and just load the model from the shared librar? This way you have proper initialization, do not abuse any parameters and have a similar flexibility (as I can judge). Moreover you have some compatibility with other (commercial) SystemC simulators. Another aspect: repeatedly calling sc_elab_and_sim() has quite some perfomance impact as there are memory allocations to hold copies the argc[] strings and some more. Best regards
  21. Hi, there is no way to do this easily. Actually you have 32 output ports and 1 input port. So you need to connect the output ports to 32 bool signals and the input port to a uint32_t signal as well and make a SC_METHOD sensitive to all of the 32 bool signals. Within that method you iterate over the 32 bool signals and collect them into a 32bit value. BTW, having a POD array of ports is not preferable, I would use 'sc_core::sc_vector<sc_core::sc_out<bool>> out;'. This way you gain several things: the ports are initialized with a name based on the sc_vector instance name and you can bind a vector of ports to a vector of signals with a single line statement. Best regards
  22. Actually in the demo part of the tutorial 'Efficient use of Virtual Prototypes in Hardware/Software Development and Verification' (slides are here) there is exactly such a case show-cased. If you go to https://git.minres.com/DVCon2018/RISCV-VP/src/branch/develop/platform/src/rtl/spi_rtl.cpp you will find a class called rtl which instantiates a verialted RTL, a bus-functional model (BFM) of the TileLink protocol, and a few more converters adapting the RTL signals. The respcetive header can be found at https://git.minres.com/DVCon2018/RISCV-VP/src/branch/develop/platform/incl/sysc/rtl The BFM implements non-blocking transport where the target socket mixin (which is similar to simple_target_socket) does the translation from blocking to non-blocking if needed. This is just since the TIleLink protocol has an explicit request and response channel (similar to AXI). In case of loosely timed model the blocking access with wait() will break your quantum thus syncronizing the time. Having several initiators with different annotated time will then change the order of accesses. You treat speed for accuracy... I hope this gives you some idea. If you have further questions feel free to ask. Best
  23. Eyck

    Read in customized structs

    Well, if this is in the same method then you won't see the update as there is not delta cylce in between. You would see it if you put it in a SC_THREAD and put a wait(SC_ZERO_TIME); between the write() and the read() of p1 and p2
  24. Eyck

    sc_port zero copy?

    There will only be one copy initialized: slave_port, simple_bus_slave_if will not be instantiated (which usually is even not possible as those are in the common case pure virtual classes). N just defines how many interface can be bound at most, 0 means unlimited. Internally there is a vector holding pointers to the simple_bus_slave_if , no copies. The vector will be resized as soon as you bind an interface. Best regards
  25. Eyck

    Read in customized structs

    Where did you check the values of p1 and p2? write() only schedules the values to be written, you will see the actual value in the next delta cycle. Best regards