Jump to content

Eyck

Members
  • Content Count

    130
  • Joined

  • Last visited

  • Days Won

    38

Eyck last won the day on December 22 2019

Eyck had the most liked content!

6 Followers

About Eyck

  • Rank
    Advanced Member

Contact Methods

  • Website URL
    http://www.minres.com/

Profile Information

  • Gender
    Male
  • Location
    Munich, Germany

Recent Profile Visitors

782 profile views
  1. Yes, it can be compiled against SystemC 2.3.3. There are even packages for Conan (conan.io) available at bintray (https://bintray.com/minres/conan-repo) where SCV is built against SystemC 2.3.3 RB
  2. How did you build and isntall SystemC? If you use cmake the file is being copied....
  3. But even in this case you register the thread only in the (inheritance) leave module. You could do: dummy_master(sc_module_name name) : ahb_master(name) { cout<<"Executing new"<<endl; SC_THREAD(ahb_master::tick); sensitive << bus_grant.pos(); } for the default behavior.
  4. 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. Your memory management is wrong. At first you pull 1 tx from the memory manager and reuse it all the time. This means you are changing your transaction in the request phase while it is in the response phase of the previous access. So you need to use mm.alloc() for each off the accesses. The purpose of the memory manager is to take care when to release/re-use the transaction. And here your second issue comes: you should always call acquire()/release() in a balanced way but your lut only calls release(). What happens then is that the transaction is pushed into the pls deque in the memory manager. Eventually you have 2x the payload in the queue and upon destruction the memory manager tries to free it 2 times. BY inserting a pl.acquire() in line 42 of lut.cpp you do not get a segfault anymore. But you should also use pl = mm.alloc() for each transaction to be send. Otherwise you might run into hard to debug functional issues. A few general comments: For performance and readability reasons you should use std::copy instead of a for loop in lut.cpp lines 51ff and 56ff Your generator needs quite some rework. Since you have always similar procedure to send a transaction extract this into some helper function (containing mm.alloc() ;-). Secondly you might think about a for loop generating the accesses as they are fairly regular Best regards
  6. 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
  7. 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
  8. 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()...
  9. 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
  10. 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
  11. 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
  12. 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; }
  13. 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. 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
  15. 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
×
×
  • Create New...