Jump to content


  • Content Count

  • Joined

  • Last visited

  • Days Won


Everything posted by Eyck

  1. Why would you want to change the address after sending it? Actually only interconnect components are allowed to change the address of an transaction (this is what the standard says). I would alwys keep in mind how this is handled in haerdware.... One option to address this is to add an extension to your transaction holding the original adress and other information you need. But this comes at the cost of interoperability (if this is a criteria for you). BR
  2. 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
  3. Well, the timer_tb gets a SC_THREAD which has exactly your sequence of writing to START and advancing time. The only difference is to use wait() instead of sc_start()...
  4. 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
  5. It would be good if you could provide a description of the problem you see (or better error messages or alike) when building the unit. I see 2 things in your code: the statement labeled with '// sensitivity list' tm << START << TIMEOUT << CLOCK; is wrong. You did this already in the constructor (SC_CTOR(timer)) of your module. The sensitivity list of your timer is wrong. The thread should only wait for the positive edge of clock, start is a data signal which is sampled/read upon the rising edge of the clock I suggest to change the implementation from a coding style point of view: add a trace function to your timer module: void trace(sc_core::sc_trace_file* tf){ sc_trace(tf, clock, clock.name()); sc_trace(tf, start, start.name); sc_trace(tf, timeout, timeout.name()); sc_trace(tf, count, (std::string(name())+".count").c_str()); } The module knows what to trace, so in your sc_main you just call tm.trace(tf); usually it is beneficial to put the stimuli stuff into a separate unit. Either a testbench instantiating and wiring your module. Or into a stimuli module where you have at sc_main only the wiring. This increases re-usability. I personally prefer the testbench approach, this unifies sc_main(): int sc_main(int argc, char* argv[]) { // testbench timer_tb tmtb("timer_tb"); // tracing: sc_trace_file *tf = sc_create_vcd_trace_file("RESULT.vcd"); tmtb.trace(tf); // simulation sc_start(); sc_close_vcd_trace_file(tf); return(!sc_core::sc_stop_called()); } The timer_tb has to call sc_stop() once it is finished with stimuli. But this is a matter of taste. BR
  6. You cannot have a delay in end_of_elaboration() or start_of_simulation() since those are callback functions outside of the (timed) simulation cycle. One thing you could do is to start the gdb within a SC_THREAD where you have a wait(SC_ZERO_TIME) to let the updates settle: void start_gdb_thread(){ wait(SC_ZERO_TIME); start_my_gdb(); } BR
  7. 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; }
  8. 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++)); }
  9. You need to connect the output port to a signal and attach a method to the signal driving the multiple output ports. So something like this: template<> struct Carries<1> : ::sc_core::sc_module { sc_vector<sc_in<bool>> a, b; sc_in<bool> rIn; sc_out<bool> p, g, rOut; sc_vector<sc_out<bool>> carries; CarryPropGen pg {"PG"}; SC_CTOR(Carries) : a {"vectA", 1}, b {"vectB", 1}, rIn {"rIn"}, p {"p"}, g {"g"}, rOut {"rOut"}, carries {"vectCarries", 1} { pg.a(a[0]); pg.b(b[0]); pg.r(rIn); pg.p(p); pg.g(g); pg.rOut(rOutS); // What I would like to do. SC_METHOD(propagate); sensitive<<rOutS.value_changed(); } sc_core::sc_signal<bool> rOutS; void propagate(){ rOut.write(rOutS.read()); carries[0].write(rOutS.read(); } }; BR
  10. If you need more flexibility than systemc-clang allows you may use libclang. This is a Python binding of the Clang library (some intro can be found here: https://shaharmike.com/cpp/libclang/ or here: https://eli.thegreenplace.net/2011/07/03/parsing-c-in-python-with-clang). This way you can easily deal with the Clang AST and its cross references and alike. Best regards
  11. Without concete code it is hard to give any advise. But it looks like that you redeclare a member function of your original module. BR
  12. 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
  13. Well, as the name says it is the data transfer with of the bus you are using. So in your case sending 128byte of data across bus having 32bits means you model a burst access having 32beats. Having said this you should notice that the bus width determines mainly the timing of a transaction. Unless you use timing for your transaction and rely on it (e.g. for performance modeling) it should not bother you. Best regrads
  14. It is spelled 'sc_spawn_options' so you missed the trailing s
  15. Without further context it is hard to give a helpful answer. You can try to do event1.notify(SC_ZERO_TIME)
  16. boost::variant would be an option or you use a union. In the latter case you loose the type safety...
  17. If you can you should do it this way. But if the source of the irq is outside of the LT domain you can only reduce the quantum.
  18. In this case you would need to add some syncronization at the ingress and the egress of the NoC. One should run with the clock of the sender and the other with the clock of the receiver. Since SystemC does not have an 'undefined' state the syncronization between ingress and egress is fairly simple depending on the way you model the way the phits/flits are send thru the NoC BR
  19. 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
  20. Another option is to use https://github.com/Minres/SystemC-Quickstart as a starting point. This gives you a cmake based project using conan to manage your libraries incl. SystemC (see README.md). Then you have 2 options (I call them 'Eclipse first' and 'CMake first'): either you install the cmake4eclipse Plugin (https://github.com/15knots/cmake4eclipse) via the Marketplace (https://marketplace.eclipse.org/content/cmake4eclipse) or you use cmake to generate your Eclipse project files via cmake -G"Eclipse CDT4 - Unix Makefiles" . I personally prefer the first approach since the latter has one drawback: if you add directory or files you have to add them in CMakeLists.txt, run the generator again and the have an updated Eclipse project.
  21. Another option would be to use a resolved signal and connect all output ports to it. But this is already about techincal implementation options. The question to me is: what would you like to model? Is this the right way to model the intend? Best regards
  22. Well, your interrpt is set in a SC_THREAD or SC_METHOD and these are active when the ISS thread sleeps. In that sense the sensing is immediate when the ISS thread wakes up. But since the ISS thread is ahead of the SystemC simulation when the irq is activated in SystemC there is no way to have an immediate sensing. This is the accuracy you give up to gain simulation speed: the delay until the ISS acts on an external event is determined by the quantum. On solution could be to use a dynamic quantum which changes in the course of the simulation: you start with a large quantum until you reach a certain point in simulation (e.g. until you booted the system) and then you lower the quantum to get more accuracy.
  23. Each type of extension has an automatically assigned ordinal number which is available per extension as ID in the base class tlm_extension. So in your case you have 2 tlm_extensions defined somewhere. Under the hood this ID is used as an index into the m_extension array of the tlm::generic_payload. Best
  24. @Philipp A Hartmann you are right, '|=' would imply and or list.
  25. @Khushi This is not a good solution since this way you enforce a quantum from a component maybe deep in the hierarchy. This sacrifies compatibility and makes reuse pretty difficult. You should follow the guidlines outlined by David.
  • Create New...