Jump to content


Popular Content

Showing content with the highest reputation since 12/05/2019 in Posts

  1. 2 points

    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
  2. 1 point
    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. 1 point
    No. For analog, SCV has not solid application.
  4. 1 point

    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
  5. 1 point
    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; }
  6. 1 point
    Hi. The never ending wait may be caused by race conditions. a) Notify with no argument means immediate notification. I.e., all processes sensitive to this event are made runnable in the same delta cycle. This may lead to non-deterministic behavior and should be used with care. Notify means all processes sensitive to this event are made runnable. The process in your case is sensitive to the event when its execution reaches the wait instruction. When the notify instruction is executed before the wait instruction is reached, no process is sensitive to the event. Event notifications are not stored for later waits. Assume the following example: p1(){ wait(ev1); cout << "wait done"; } p2(){ ev1.notify(); } When p1 starts first, it executes until wait is reached. Then p1 is suspended and p2 continues. The notification of ev1 is executed, p1 is made runnable again, and the message is printed. When p2 starts first, the notification of ev1 is done without any process waiting. Hence, it has no effect. Then p1 is started. It reaches the wait statement and will wait forever because the event notification has been executed before. No message will occur. Since SystemC contains no guaranty about the order in which processes runnable in the same delta cycle are executed, a model like the example leads to non-deterministic behavior. Greetings Ralph
  • Create New...