Jump to content

Eyck

Members
  • Posts

    356
  • Joined

  • Last visited

  • Days Won

    87

Reputation Activity

  1. Thanks
    Eyck got a reaction from Amol Nikade in 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.
  2. Like
    Eyck got a reaction from swami-cst in 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. Thanks
    Eyck got a reaction from SiGa in Debug assertion fails when using sc_trace   
    You create 5 signals carrying a TraceVector. Doing so the default constructor is used which does reserve space for elements but has a size of 0...
    I can't tell where the assertion comes from. For those cases a debugger is pretty helpfull B-)
  4. Like
    Eyck got a reaction from swami-cst in HERITAGE on a SC_MODULE with THREAD   
    You are defining a thread in ahb_master and a thread in dummy_master where both have the same name (tick) but a different C++ signature (ahb_master::tick and dummy_master::tick).
    Actually defining the tick thread in ahb_master doesnt make any sense, moreover since it doesn't do anything it will be declared immediately after simulation start.
    BR
  5. Thanks
    Eyck got a reaction from Nitin_S in Introducing wait/delay in end of elaboration of start of simulation   
    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
  6. Thanks
    Eyck got a reaction from plafratt in Handling of Requests with Early Responses when Initiator Can Change Transaction   
    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
  7. Thanks
    Eyck got a reaction from bad63r in [SOLVED] How to send float value with LT TLM2.0 and read it back   
    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. Like
    Eyck got a reaction from Mik in 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
  9. Thanks
    Eyck got a reaction from Zoumson in sc_main function for timer in SystemC   
    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
  10. Like
    Eyck got a reaction from swami-cst in 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
  11. Like
    Eyck got a reaction from swami-cst in [SOLVED] How to send float value with LT TLM2.0 and read it back   
    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; }  
  12. Like
    Eyck got a reaction from David Black in How to trace std::list<int> with sc_trace? [solved]   
    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++)); }  
  13. Thanks
    Eyck got a reaction from SiGa in How to trace std::list<int> with sc_trace? [solved]   
    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++)); }  
  14. Like
    Eyck got a reaction from DS1701 in 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
  15. Thanks
    Eyck got a reaction from SiGa in 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...
  16. Thanks
    Eyck got a reaction from SiGa in 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
  17. Like
    Eyck got a reaction from David Black in bind multi ports to other port.   
    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
  18. Thanks
    Eyck got a reaction from ArjunMadhudi in Static Sensitivity to "AND" of two events   
    You would want to use an sc_event_and_list. See IEEE1666 section 5.8. As its intended use is with next_trigger() and wait() you would need to move the sensitivity into your method. So the constructor part becomes
    SC_METHOD(func2); and func2 should something like (snippet of your module):
    sc_core::sc_event_and_list ev_list; void end_of_elaboration(){ ev_list |= clk.posedge_event(); ev_list |= nreset; } void func2(){ next_trigger(ev_list); // your code here ... }  
  19. Thanks
    Eyck got a reaction from andrewkrill in Issues with concurrency and running C++ code on top of SystemC   
    Hmm, not sure if I understand you correctly. Your C++ code has an entry function, right? If you just call this entry function from a SC_THREAD it runs in a thread context and can call wait to let other parts of the simulation continue.
    The other option you have is to run your C++ code in a second (OS) thread, e.g. a std::thread. This allows to use the usual syncronization primitives of the OS like mutexes and alike.
    BR
  20. Like
    Eyck got a reaction from swami060 in How to ensure handling interrupt in time when using quantum keeper?   
    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.
  21. Like
    Eyck got a reaction from shubham_v in tracing waveforms in tlm   
    You may use the tlm recorder of the SystemC components lib (SCC, esp. here: https://git.minres.com/SystemC/SystemC-Components/src/branch/master/incl/scv4tlm). This writes into a text database (the SCV default). You can view this e.g. with Impulse (https://toem.de/index.php/projects/impulse) or SCViewer (https://git.minres.com/VP-Tools/SCViewer, binaries here: https://github.com/Minres/SCViewer/releases).
    Basically you instantiate scc::tlm2_recorder_module and connect it's initiator and target sockets. to your target and initiator socket. Your sc_main should then look like:
    int sc_main(int argc, char *argv[]) { scv_startup(); scv_tr_text_init(); scv_tr_db db("my_db.txlog"); scv_tr_db::set_default_db(&db); dut_mod dut("dut"); sc_start(1.0, SC_MS); return 0; } The database is closed upon destruction of the db object.
    Best regards
  22. Like
    Eyck got a reaction from David Black in multiple initiator sockets and single target socket   
    From the snippets you provide it looks ok.
    Assuming that bus_mutex is a sc_mutex this is you problem. sc_mutex does not do arbitration. It selects randomly which waiting thread to grant the lock (actually the next activated process base on an even notification) . But what you expect is arbitration. So either you write an arbiter or you may use and ordered semaphore with an initial counter value of 1. You may find an implementation here: https://git.minres.com/SystemC/SystemC-Components/src/branch/master/incl/scc/ordered_semaphore.h
    The semaphore grant access based on a queue. So eventually you get first-comes-first-serves (FCFS) behavior, but all requestors have equal priority.
    Best regards
  23. Like
    Eyck got a reaction from DS1701 in 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
  24. Like
    Eyck got a reaction from shubham_v in tlm model with clocks & code sample   
    My fault, SC_THREAD has a sensitivity list and you can call wait() for the default event. In my experience -and this guided my answer- it is better to have no sensitivity list and wait explicitly for events.
    When specifying a port in the sensitivity list you need to use an event finder (with .pos()) as the port is not bound yet and hence does not have an event associated. In the thread itself you can use the pos_edge event. So your code shown above is correct.
    BR
  25. Like
    Eyck got a reaction from shubham_v in tlm model with clocks & code sample   
    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
×
×
  • Create New...