Jump to content

Eyck

Members
  • Posts

    356
  • Joined

  • Last visited

  • Days Won

    87

Everything posted by Eyck

  1. Well, actually a scenaron having a sc_main linking various shared objects which in turn reference the SystemC library as shared object works. So I suspect you build process is somehow wrong. To help you here you would need to post the your build log or at least the linker calls for your user and util liba and for your executable. Best regards
  2. You should consult the LRM again.:SC_THREAD does not have a sensitivity list. Moreover you create a memory leak creating the transaction object using new and not deleting it. And your thread ends after 10 accesses. Basically you need to wait for the clock explicitly while (1) { // wait for the rising edge wait(clk.posedge_event()); tlm::tlm_generic_payload trans; // setup the transaction ... // execute the access i_socket->b_transport(*trans, delay); } In your solution the loop in your threads are based on timed delays hence it is not reactiong on your clocks at all. Best regards
  3. Your trace function calls sc_trace(sc_trace_file *, sc_object*, const char*) which is not overloaded and hence issues the warning. You would need to test for each single template instance of sc_signal<T> and then call the appropriate sc_trace function. And example you can find in https://git.minres.com/SystemC/SystemC-Components/src/branch/master/src/tracer_base.cpp#L90. Or you may use the SystemC Components Library (SCC) as a whole since it provides already this functionality. Best regards
  4. At https://git.minres.com/DVCon2018/RISCV-VP/src/branch/develop/platform/src/rtl and https://git.minres.com/DVCon2018/RISCV-VP/src/branch/develop/platform/incl/sysc/rtl you may find some example of an integration of a cycle-based model (Verilator+Verilog RTL) into a VP using LT-style modelling. This is from last-years DVCon Europe (http://events.dvcon.org/events/proceedings.aspx?id=260--3-T). Best regards
  5. 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
  6. Absolutely agreed. But to my experience folks try to avoid that as much as possible as it complicates the often already complicated protocol implementation. BR
  7. 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
  8. Well, to me it is always helpful to think about sockets as a proxy or sophisticated function forwarder (in some sense similar lto sc_port). So you call b_transport on the initiator side and the socket forwards the call to the target and invokes b_transport there. HTH
  9. 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
  10. Hi, TLM2.0 is used to model bus-like transactions as you have in APB, AHB, AXI or alike. It abstracts those transactions in to e.g. read and write with some attribites (liek protection and alike). This saves some from dealing with bit wiggling and, as you have less events, improves simulation performance. If you use in your scenarion fifo between your producer and consumer you are already using TLM as you abstract the transmission of more or less complex data as a write into the fifo. If you keep this style in your design you do transaction level modeling (TLM). If you are asking if it makes sense to use the TLM2.0 standard is a different question and depends on what aspects of your design do you need to represent in your model. If you have some kind bus structure (e.g. some micro processor or controller) then it is highly advisable to use TLM2.0. In that case your producer calls the transfer functions of the initiator socket and your consumer needs to react on the callbacks of the target socket. Actually this does not relate to your file structure but as a starting poitn I would suggest to study the lt example comign with the SysetmC distribution. You will find it under examples/tlm/lt, it contains 2 initiator_top mdouels, a bus and 2 lt_target modules. if you reduce the thing to just one initiator_top and one lt_target being directly connected you have your producer/consumer scenario. HTH
  11. Hi, deleting a binding is not supported. You did not detail your scenario in terms of producer and consumer. Ports in itself are only some kind of a proxy or function-forewarder. So if you have a producer having a sc_out you cannot bind it to some sc_in port of a consumer. You alway have to have a signal in between. Or in terms of C++ a port just forwards function (an interface) but you need to have an element implementing or providing these functions (an implementation). Bottomline: To connect some producer/writer to a consumer/reader thus fowarding a signal write you need to have a signal in between. Best regards
  12. You should not use new on arrays as this does not call the constructors. So instead of sc_in<bool> * task_finished; You should use sc_vector< sc_in<bool> > task_finished; and the constructor should the look like TaskSchedulerTemplate::TaskSchedulerTemplate(sc_module_name name, std::vector<PipelineLeon*> * _pipelines) : sc_module(name), task_finished("task_finished", number_of_pipelines), pipelines(_pipelines) { SC_METHOD( schedule_task ); sensitive << trigger_task_scheduler; dont_initialize(); for (vector<PipelineLeon*>::iterator pipeline = pipelines->begin() ; pipeline != pipelines->end() ; pipeline++ ){ task_finished[ (*pipeline)->get_cpu_index() ]( (*pipeline)->task_finished ); } SC_METHOD(task_finished_action); for (int i = 0; i< number_of_pipelines; i++) { sensitive << task_finished[i].pos(); } dont_initialize(); } sc_vector ensure that the constuctors of the sc_port are called properly. Moreover I would not bing the task_finished signals of the _pipeline vector in the constructor, this limits the reuse and the clarity of the design intent. So I suggest to move the for-loop to sc_main and remove the second constructor argument to TaskSchedulerTemplate::TaskSchedulerTemplate. BR -Eyck
  13. But since these are multi_passthru sockets the id indicates the number of the bound initiator socket (as the multi_passthru_target_socket can bind several sockets to one). BR
  14. You cannot not check typeid() against a string as this is compiler dependend. What you shoudl do is void write_out{ if(typeid(T) == typeid(sc_dt::sc_logic){ out.write(SC_LOGIC_Z); }else{ out.write(0); } } } But actually this is more a C++ related question, in my experience Stackoverflow is a good source of help. Cheers
  15. 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.
  16. 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
  17. 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
  18. 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
  19. 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
  20. 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
  21. 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
  22. 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
  23. 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
  24. 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
  25. 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.
×
×
  • Create New...