Jump to content

Roman Popov

  • Content count

  • Joined

  • Last visited

  • Days Won


Everything posted by Roman Popov

  1. Roman Popov

    Seeking Feedback on Datatypes

    Some thoughts on these topics: During elaboration any C++ should be supported, including standard library. Language/library restrictions should only be imposed on process bodies (SC_THREADs and SC_METHODs). Otherwise SystemC synthesis would not be competitive vs languages focused on structure generation. Some design teams are already switching from SystemC to Chisel due to limitations in SystemC tools. std::array can be supported, but adds little value compared to C-style arrays. sc_vector should be supported. But unfortunately it only supports sc_object types. So I can't for example create sc_vector<sc_int<32>> to model RAM with elaboration-time defined size. std::vector allows expansion during simulation, that won't be synthesizable. I think it would be a good idea to extend sc_vector with non-sc_object types support. Also more flexible API can be added, like emplace_back(...) for elaboration-time programming. Attributes can't be used with template-based compile-time programming and elaboration-time programming. Macros will be the only way to program with attributes. That is bad. Instead, why not to to standardize a set of functions to pass synthesis directives? As usual, there is a compromise between simulation performance and flexibility of usage. I looked through proposals, and I think it would be nice to have both AC datatypes and improvement to existing bigint SystemC datatypes. From flexibility perspective, sc_unsigned and sc_signed are ideal, because they can be used both with template-based meta-programming and elaboration-time programming. So we have the same structural programming flexibility as in Chisel or MyHDL. AC datatypes are less flexible, but more efficient.
  2. Can't reproduce on my machine (Ubuntu 16.04, gcc 6.3). Probably something specific to Ubuntu 18.04. Can you check with some older OS?
  3. Roman Popov

    SystemVerilog "program" scope

    You can create a delayed clock signal that can be used to synchronize testbench threads. With a delta cycle delay you can achieve a behavior you want (enforce all testbench processes to be evaluated on next delta cycle after DUT process). However, such a test environment won't be reusable for non-verilated code (RTL simulation with commercial Verilog simulators, Gate-level simulation, etc). In a RTL design with a single clock domain Verilator converts all Verilog processes into a single SystemC clocked SC_METHOD. This SC_METHOD executes in a single delta cycle. However, in other Verilog simulators each Verilog process will be executed separately. For example, there can be a combinatorial logic process that can introduce arbitrary number of delta-cycle delays between clocked process in DUT and testbench. So sampling with a delta-cycle delay will not work. In a timing-aware gate-level simulation delay can be any time period less then a clock period (if design meets timing constraints). In that case sampling on a falling edge of a clock may not work. Canonical solution to this problem is to sample output on the next clock cycle. So, for example, to test a single D flip-flop you will need 3 clock cycles: On a 1st clock cycle test sets input data, on a 2nd cycle DFF captures input data, on a 3rd clock cycle test verifies DFF output data.
  4. Roman Popov

    SystemVerilog "program" scope

    I don't know much about SystemVerilog scheduling, but in SystemC there is no difference between RTL code and testbench code. So you should not rely on order of process evaluation inside a single delta cycle. In practice, I also use Verilator for verification of HLS-generated Verilog designs, but I've never needed a delayed sampling. Verilator does not introduce any additional delays to model so I can use original SystemC testbench as is. Why do you need delayed sampling?
  5. Roman Popov

    Support for C++11/14 in SystemC 2.3.2

    --Deleted-- I've re-read original post from Philipp and it provides detail explanation why it was made this way.
  6. No. Only assignment (or write() method) triggers update request. Constructor initializes signal value directly. So sig0 constructor generates no events and method1 is not activated.
  7. Roman Popov

    Support for C++11/14 in SystemC 2.3.2

    Most likely you have C++98 in CMake cache. You don't need to modify SystemC CMakeLists, just set c++ standard from command line. Check here for detailed instructions https://stackoverflow.com/questions/46875731/setting-up-a-systemc-project-with-cmake-undefined-reference-to-sc-core
  8. Here is an example illustrating initialization semantics. #include <systemc.h> SC_MODULE(test_init) { SC_CTOR(test_init) { SC_METHOD(method0); SC_METHOD(method1); sensitive << sig0; dont_initialize(); SC_METHOD(method2); sensitive << sig1; dont_initialize(); sig1 = 1; } void method0() { cout << "method0\n"; } sc_signal<int> sig0{"sig0",42}; void method1() { cout << "method1 sig0 == " << sig0 << endl; } sc_signal<int> sig1{"sig1"}; void method2() { cout << "method2 sig1 == " << sig1 << " sig0 == " << sig0 << endl; } }; int sc_main (int argc, char**argv) { test_init mod{"mod"}; sc_start(); return 0; } Simulation output: method0 method2 sig1 == 1 sig0 == 42 I think it covers both questions.
  9. Yes, this is how reference open-source SystemC kernel is implemented. You can compile SystemC in debug mode and step into wait(t) inside debugger to see for yourself. Such an implementation is not mandatory by SystemC standard, but afaik most commercial SystemC simulators are derived from reference one and most likely are implemented in the same way.
  10. In general, there is no such concept as a "list of sleep processes" in SystemC. Because, really, all processes are sleeping, except the one that is currently evaluated. For scheduling, there are two "lists" that simulator needs to maintain (my interpretation of LRM 4.2.1): Set of runnable processes - that are process that will be evaluated in a current evaluation phase (current delta cycle). Event notification queue, where notifications are prioritized by time. First come delta notifications (The set of delta notifications and time-outs), then timed notifications, prioritized by notification time (The set of timed notifications and time-outs) Probably the source of confusion here, is when you call wait(0,SC_NS) you don't see any event. But in fact there is a hidden "internal" event that you notify when you call wait(). This hidden event implements "time-outs". > Yes, wait(X, SC_NS) works the same way as event.notify(X,SC_NS). SystemC scheduling is all about event notifications. There are 3 types: event.notify() - Immediate notification. This will put all processes subscribed to event into set of runnable processes. That is, they will be executed in the current delta cycle. event.notify(SC_ZERO_TIME) - Delta notification. This will put delta event notification into event notification queue. event.notify( sc_time > 0 ) - Timed notification. This will put timed event notification into event notification queue.
  11. This is unexpected. Probably you don't see a full simulation log or your simulator has a bug. Try to add delta cycle counts to log: void p1(void) { while (true) { cout << "p1: " << sc_time_stamp() << " delta " << sc_delta_count() << endl; wait(0, SC_NS); } } void p2(void) { while (true) { cout << "p2: " << sc_time_stamp() << " delta " << sc_delta_count() << endl; wait(0, SC_NS); } }
  12. Roman Popov

    Error during installation

    Did you configured it with pthreads as described in release notes? In general, if possible you should use Visual Studio or MinGW on Windows. Cygwin is not widely used with SystemC so some bugs are possible. Also SystemC with cygwin/pthreads is much slower then with fibers.
  13. Roman Popov

    The conceptual behavior of sc_in<>

    Simulation semantics is described in SystemC standard, paragraph 4.2 Simulation. sc_signal is particular kind of primitive channel, it's value is updated in Update phase. You don't need to wait for delta cycle in your SC_THREAD. Most likely your signal value changes multiple times, but you catch only first change (the one you don't expect). Try to rewrite your thread with with inifinite loop to catch all signal change events: void XXX::InputChanged() { while (1) { cerr << '@' << sc_time_stamp() << ' ' << Address<< endl; } }
  14. Roman Popov

    SystemC generator

    Most of the tools do the opposite: convert SystemC into schematic... But in case you have a schematic in some machine-readable format it should be pretty straightforward to generate SystemC netlist.
  15. Roman Popov

    Passing event to SC_CTHREAD macro

    There is a difference: in SC_CTHREADs you can't wait on event. Since this would not be synthesizable. sc_clock clk{"clk", 1, SC_NS}; SC_CTOR(test) { SC_THREAD(test_thread); sensitive << clk.posedge_event(); SC_CTHREAD(test_cthread, clk); } void test_thread() { wait(clk.negedge_event()); // OK } void test_cthread() { wait(clk.negedge_event()); // RUNTIME ERROR } So I always use SC_CTHREADs in synthesizable code, to specify my intent and prevent accidental calls to non-synthesizable methods with wait(event). Indeed, did not know about it. This works for me. In my practice I did not yet encountered a case where I need to create a CTHREAD sensitive to negedge.
  16. Why SystemC does not allow to pass event directly to SC_CTHREAD macro? For example: #include <systemc.h> SC_MODULE(test) { sc_clock clkgen{"clkgen", 10, SC_NS}; sc_in_clk clk{"clk"}; SC_CTOR(test) { clk(clkgen); SC_CTHREAD(test_cthread, clk.pos()); // OK SC_CTHREAD(test_cthread, clkgen.posedge_event()); // Compile error! } void test_cthread(); }; If I inline macro I can do what I want: { ::sc_core::sc_process_handle test_cthread_handle = sc_core::sc_get_curr_simcontext()->create_cthread_process( "test_cthread", false, static_cast<sc_core::SC_ENTRY_FUNC>(&SC_CURRENT_USER_MODULE::test_cthread), this, 0); /// this->sensitive.operator()(test_cthread_handle, clkgen.posedge_event()); /// Error sc_sensitive::make_static_sensitivity(test_cthread_handle,clkgen.posedge_event()); /// OK }; This looks to me as inconvenience without a good reason.
  17. Roman Popov

    How SystemC kernel is implemented !!

    SC_THREADS are coroutines https://en.wikipedia.org/wiki/Coroutine. SystemC uses different coroutines implementations depending on platform (Fibers, QuickThreads..). Function of sc_simcontext is not standartized. But in open-source SystemC it contains main simulator loop.
  18. Roman Popov

    How SystemC kernel is implemented !!

    You should probably read a book about multi-threaded programming to understand what thread means. A good book about standard C++ threads is C++ Concurrency in Action by Anthony Williams. SystemC is indeed a single thread. Most of other cycle-accurate (RTL) and TLM simulators are also single-threaded. In theory, you can write a parallel scheduler that can utilize multiple HW threads to evaluate a single delta-cycle (because SystemC standard does not restrict the order of process evaluation inside delta cycle) . However, amount of work performed in a single delta cycle is usually small, so instead of speedup you will get a slow down. To utilize power of multicore CPUs you should parallelize your test environment. Instead of running multiple tests sequentially in a single simulator, you can run different tests in parallel on different simulators. Personally, I integrate my tests with CTest : https://cmake.org/cmake/help/latest/manual/ctest.1.html and then run in parallel simply by specifying number processes I want to utilize, for example "ctest -j 8"
  19. Roman Popov

    sc_spawn and anthoer process

    If you want to pass a parameter to process, then you can use sc_spawn and std::bind to bind parameters.
  20. Roman Popov

    Graph Generation

    In some cases yes, you can do it by playing with dynamic casts. For example: #include <systemc.h> SC_MODULE(test) { sc_signal <int> xsig{"xsig"}; sc_signal <unsigned> xsig2{"xsig2"}; sc_in <int> xin{"xin"}; sc_out <unsigned> xout{"xout"}; SC_CTOR(test) { xin(xsig); xout(xsig2); } }; int sc_main(int argc, char **argv) { test t0{"t0"}; sc_start(SC_ZERO_TIME); cout << hex; for (auto * obj : t0.get_child_objects()) { cout << obj->kind() << " " << obj->name() << " @ " << obj; if(sc_port_base* port = dynamic_cast<sc_port_base*>(obj)) if (sc_prim_channel * chan = dynamic_cast<sc_prim_channel*>(port->get_interface())) std::cout << " ( binded to " << chan->name() << " @ " << chan << ")"; cout << endl; } return 0; } Possible output: sc_signal t0.xsig @ 0x111f878 sc_signal t0.xsig2 @ 0x111f938 sc_in t0.xin @ 0x111f9e8 ( binded to t0.xsig @ 0x111f878) sc_out t0.xout @ 0x111fa90 ( binded to t0.xsig2 @ 0x111f938) SystemC however does not store information about hierarchical bindings.
  21. Roman Popov

    sc_spawn and anthoer process

    sc_spawn allows to create process during simulation runtime. SC_* macro can be used only at elaboration time. Please read more details in IEEE SystemC standard. Here is small usage example: #define SC_INCLUDE_DYNAMIC_PROCESSES #include <systemc.h> SC_MODULE(spawn_demo) { SC_CTOR(spawn_demo) { SC_THREAD(static_thread); } void static_thread() { sc_spawn_options opts; sc_spawn([&]() { wait(1, SC_NS); cout << "spawned @ " << sc_time_stamp() << "\n"; }, "spawned_thread", &opts); wait(1, SC_NS); cout << "static @ " << sc_time_stamp() << "\n"; } }; int sc_main(int argc, char **argv) { spawn_demo demo0{"demo0"}; sc_start(); return 0; }
  22. Roman Popov

    Implement sc_trace for std::string

    Unfortunately current implementation was not designed to be extensible by user. So you will have to hack SystemC kernel itself. Tracing part is relatively small so it's should not be very hard. Just follow the implementation for existing types. In general however it should be better to redesign tracing API so it will be extensible for user-supplied types. In addition to accepting fixed set of datatypes, it should also accept abstract interfaces that can be implemented by end user. For example: // currently does not exist struct BitVecConvertible { virtual sc_dt::sc_bv_base to_bv() = 0; } sc_trace(sc_trace_file* tf, BitVecConvertible &obj, onst std::string& name); In that case user can trace any type as a bit vector, by implementing an interface or providing a proxy-class.
  23. Roman Popov

    Possible Bug in VCD tracing

    Thanks for reporting! Here is a small reproducer for this bug: #include <systemc> int sc_main(int argc, char ** argv ) { sc_core::sc_trace_file *tf = sc_core::sc_create_vcd_trace_file("vcdtrace"); sc_core::sc_close_vcd_trace_file(tf); return 0; } Probably the easiest way to fix is to do zero check before printing last time stamp.
  24. The problem is that both sockets are binded to same target interface implementation. So: In[0].get_interface() == In[1].get_interface(); When you bind same interface twice to a single port, SystemC considers this a design error. Solution depends on your modeling needs. Usually TLM sockets are connected point-to-point and to model interconnect a separate module that forwards transactions from initiator to targets is created.
  25. You can use sc_vector: sc_vector<tlm_utils::multi_passthrough_initiator_socket<Router, 32, tlm::tlm_base_protocol_types,1,sc_core::SC_ZERO_OR_MORE_BOUND >> Out{"Out", 10};