Jump to content

Roman Popov

Members
  • Posts

    353
  • Joined

  • Last visited

  • Days Won

    47

Everything posted by Roman Popov

  1. Ok, I understood what you mean. Yes, looks like waveform will always end at the moment last signal change happened. Here is my test: SC_MODULE(test) { sc_signal<bool> data{"data"}; SC_CTOR(test) { SC_THREAD(test_thread); } void test_thread() { data = true; wait(1, SC_US); data = false; wait(1, SC_US); data = true; wait(1, SC_US); } }; int sc_main(int, char**) { test test_inst{"test_inst"}; sc_trace_file *fp; fp=sc_create_vcd_trace_file("wave"); sc_trace(fp,test_inst.data,"data"); sc_start(); sc_close_vcd_trace_file(fp); cout << "simulation finished at " << sc_time_stamp() << endl; return 0; } At console I get: simulation finished at 3 us But in VCD there will be only 2 us of waveform trace. I think is a bug/limitation of opensource SystemC. In commercial simulator (Synopsys VCS) I observe full waveform of 3 us.
  2. There is a problem with implementation of in-place binding I've suggested in previous post: it does not respects the fact that signals may not be constructed by the time biding function is executed. So it is better to delay binding until everything is constructed. Here is better implementation: struct my_sc_module : public sc_module { typedef std::function<void()> bind_func_t; bind_func_t bf; my_sc_module( bind_func_t bind_func ) : bf(bind_func) {} void before_end_of_elaboration() override { if (bf) bf(); } }; #define SC_MODULE(user_module_name) \ struct user_module_name : my_sc_module #define SC_CTOR(user_module_name) \ typedef user_module_name SC_CURRENT_USER_MODULE; \ user_module_name( ::sc_core::sc_module_name , bind_func_t bind_func = 0) : my_sc_module(bind_func) SC_MODULE(adder) { SC_CTOR(adder) { SC_METHOD(add_method); sensitive << a << b; } void add_method() { sum = a + b; } sc_in<uint8_t> a{"a"}, b{"b"}; sc_out<sc_uint<9> > sum{"sum"}; }; SC_MODULE(adder_test) { sc_signal<uint8_t> *a; adder add_inst{"add_inst", [&]() { add_inst.a(*a); add_inst.b(; add_inst.sum(sum); } }; SC_CTOR(adder_test) { a = new sc_signal<uint8_t>("a"); SC_THREAD(test_thread); } void test_thread() { a->write(11); b = 31; wait(1, SC_PS); cout << sum.read() << endl; sc_stop(); } sc_signal<uint8_t> b{"b"}; sc_signal<sc_uint<9>> sum{"sum"}; }; int sc_main(int, char**){ adder_test test("test"); sc_start(); return 0; }
  3. Often there are two reasons for simulation to stop: 1) It has nothing left to do. 2) Some error happens If you want to run simulation for specific time, you can use sc_start with parameter, for example: sc_start( sc_time(100, SC_NS) );
  4. Than you have a typo in another place: class target : public sc_module { public: sc_export<sc_signal_in_if<bool> > in; ---- > Change to sc_export<sc_signal_inout_if<bool> > in; sc_signal<bool> sig; target(sc_module_name name){in(sig);} }; The problem is that you try to bind port and export with different interfaces
  5. I think you just have a typo here: int sc_main(int, char**) { initiator init("init"); target targ("targ"); init.out(targ.in); --> Should be init.out(targ.sig); sc_start(); return 0; }
  6. Hello, Is any facelift planned for next SystemC release (2.4 or 3.0)? I want to share some feedback , from synthesizable SystemC designer prospective. Recently I’ve done a lot of synthesizable SystemC coding for HLS (High level synthesis tools). I really enjoy the power of synthesizable stateful threads (SC_THREADS), it helps a lot in converting algorithmic C++ code into RTL. TLM abstraction of synthesizable bus interfaces works well too. However, If you look at low level syntax details, SystemC code looks really ugly comparing to Verilog. Consider a simple example: module adder ( input [7:0] a, b, output [8:0] res ); assign res = a + b; endmodule module adder_test; reg [7:0] a, b; wire [8:0] res; adder adder_isnt( .a(a), .b(, .res(res) ); initial begin a = 11; b = 31; #1; $display("%d",res); end endmodule If I rewrite in SystemC it would be: #include <systemc.h> SC_MODULE(adder) { sc_in<uint8_t> a, b; sc_out<sc_uint<9> > sum; SC_CTOR(adder) : a{"a"} , b{"b"} , sum{"sum"} { SC_METHOD(add_method); sensitive << a << b; } void add_method() { sum = a + b; } }; SC_MODULE(adder_test) { sc_signal<uint8_t> a, b; sc_signal<sc_uint<9>> sum; adder add_inst; SC_CTOR(adder_test) : a("a") , b("b") , sum("sum") , add_inst("add_inst") { add_inst.a(a); add_inst.b(; add_inst.sum(sum); SC_THREAD(test_thread); } void test_thread() { a = 11; b = 31; wait(1, SC_PS); cout << sum.read() << endl; sc_stop(); } }; Main problem is not that SystemC code has more charaters/LOCs, but that semantically related statements are distributed across source file. Take for example adder instantiation: First we have to declare member variable: adder add_inst; Next we need to initialize its name: : add_inst("add_inst") And finally bind its ports: add_inst.a(a); add_inst.b(; add_inst.sum(sum); Because of this syntactic problem it is very hard to read SystemC code when you have a lot of signals and modules instantiated. Same problem with SC_METHOD and SC_THREAD: You have to define method in one part of code, and declare it as a SC_METHOD/SC_THREAD in another. I often forgot to put this SC_THREAD macro and my simulations do not work. Forgetting sc_module_name initialization is even more common (but does not do that much damage). So there are two problems with SystemC syntax: Code hard to read. Easy to forget something. I hope this will be fixed soon. If I start to think about it , I see two possible options: Option 1: Preprocessing First solution would be creating some SystemC preprocessor. It's not that uncommon idea in C++ world. For example widely used Qt Framework (http://www.qt.io/) uses it’s own preprocessor. Some EDA SystemC tools use it too: Forte Cynthesizer used preprocessor to extract uArch constraints from some vendor predefined Macros, I think Cadence Stratus inherited this HLS Macro idea too (have not tried it yet). The obvious argument against this would be breaking C++ tools compatibility (for example C++ IDE front-ends). But it’s not always the case: Qt and HLS preprocessors do not break C++ syntax, syntactically valid SystemC code will stay a valid C++ code. But some C++ static analysis tools may break: for example, if we generate body of sc_module constructors in preprocessor, than we will have some “unreachable” code, “unused” methods detected in human-written code. Second argument against preprocessor is that user will need to integrate additional step into C++ build process. Sometimes it hurts, many users do not like to write custom build steps. Main benefit in preprocessing is that it solves all the problems. It would be even possible to automatically generate sensitivity lists for SC_METHODS (in that case it it would be very smart Clang-based preprocessor), highly desired. http://forums.accellera.org/topic/5430-what-is-always-verilig2001-equivalent-syntax-in-systemc/ Option 2: Improve SystemC library Many things can be done simply by improving SystemC library. In that case we will be limited by C++ meta-programming capabilities. Ultimate solution to sc_object naming will be C++ reflection: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4451.pdf But my bet it would not be standardized in next five years or so. Probably some EDA or semiconductor company can devote some resources to make it happen sooner? Many things are better out-of-the box in C++11, For example in-class initializers: sc_signal<uint8_t> a{"a"}, b{"b"}; sc_signal<sc_uint<9>> sum{"sum"}; I use it now in all of my SystemC verification code. Unfortunately not yet supported by HLS tool I use. David Black proposed solution for assign http://nascug.org/events/17th/black_cpp11_2_27_2012.pdf Same idea with lambda can be applied to every SC_METHODS/SC_THREAD processes. Binding instance ports can be implemented in the same place where instance defined. Consider for example passing “bind” lambda using in-class initializer: #define SC_CTOR(user_module_name) \ typedef std::function<void(user_module_name& self)> bind_func_t; \ typedef user_module_name SC_CURRENT_USER_MODULE; \ user_module_name( ::sc_core::sc_module_name, bind_func_t bindf= 0) \ { if (bindf) { bindf(*this); } #define BIND_INST(module_type) \ [&](module_type& i) Summing all together improved SystemC can probably look like: SC_MODULE(adder) { sc_in<uint8_t> a{"a"}, b{"b"}; sc_out<sc_uint<9> > sum{"sum"}; SC_CTOR(adder) { ASSIGN( a|b, sum = a + b; ); } }; SC_MODULE(adder_test) { sc_signal<uint8_t> a{"a"}, b{"b"}; sc_signal<sc_uint<9>> sum{"sum"}; adder add_inst{"add_inst", BIND_INST(adder) { i.a(a); i.b(; i.sum(sum); }}; SC_CTOR(adder_test) { SC_THREAD_LAMBDA(test_thread) { a = 11; b = 31; wait(1, SC_PS); cout << sum.read() << endl; sc_stop(); } } };
  7. There is an ASSIGN implementation proposal in: http://nascug.org/events/17th/black_cpp11_2_27_2012.pdf So with bit level access to sc_signals I can imagine something like: ASSIGN( addr_sig, a_sel_sig = addr_sig[0] ); ASSIGN( addr_sig, b_sel_sig = addr_sig[1] ); ASSIGN( addr_sig, c_sel_sig = addr_sig[2] ); or even ASSIGN( addr_sig[0], a_sel_sig = addr_sig[0] ); ASSIGN( addr_sig[1], b_sel_sig = addr_sig[1] ); ASSIGN( addr_sig[2], c_sel_sig = addr_sig[2] ); if sc_signal[] returns something with event capabilities Highly desired for Synthesizable SystemC.
  8. I don't understand your comment. I'm constantly using sc_signals for thread synchronization inside single module.
  9. A follow-up question for http://forums.accellera.org/topic/5443-vector-declaration/ Why square brakets are not overloaded for sc_signal class? In case underling datatype allows bit-level access, it seems it would be handy to allow it for signals? Looks like there is no technical limitation to do this, here is an example: #include <systemc.h> template< class T, sc_writer_policy POL = SC_DEFAULT_WRITER_POLICY > struct my_sc_signal : public sc_signal<T, POL> { typedef my_sc_signal<T,POL> this_type; typedef sc_signal<T, POL> base_type; explicit my_sc_signal( const char* name_) : base_type( name_ ){} struct signal_writer_helper { signal_writer_helper (this_type &s, size_t i) : sig(s), id(i) {} template <typename AT> void operator = ( const AT& val_ ) { bool value_changed = !( sig.m_cur_val[id] == val_ ); sig.m_new_val[id] = val_; if( value_changed ) sig.request_update(); } this_type &sig; size_t id; }; signal_writer_helper operator [](size_t i) { return signal_writer_helper(*this, i); } }; SC_MODULE(test) { static const int BUS_WIDTH = 10; my_sc_signal<sc_uint<BUS_WIDTH> > test_sig{"test_sig"}; SC_CTOR(test) { SC_THREAD(master_thread); SC_METHOD(slave_method); sensitive << test_sig; } void master_thread() { for (int i = 0; i < BUS_WIDTH; ++i) { test_sig[i] = 1; wait(1, SC_NS); } for (int i = 0; i < BUS_WIDTH; ++i) { test_sig[i] = 1; wait(1, SC_NS); } sc_stop(); } void slave_method() { cout << "New signal value is: " << test_sig.read() << endl; } }; int sc_main(int argc, char *argv[]) { test test_inst("test_inst"); sc_start(); return 0; }
  10. The problem is that square brackets operator is not overloaded in sc_signal. Because of that you can't do bitwise operations on sc_signals. I don't know the exact technical reason why it is not allowed in SystemC. Implementing it will be challenging, but it does not look impossible.
  11. Unfortunately I had not time to try UVM-SystemC for our SystemC project. But overall some SystemC verification framework is desired. Currently we apply some UVM-inspired ideas in our SystemC testbenches. I've reviewed test examples, everything works well under Ubuntu 14.04 with GCC 4.8.
  12. Have not checked you example, but as you've said, you can't force method exectution order in same delta cycle. So you will have to put execution in different delta cycles, by implementing some sort of syncrhonization between methods, using sc_event or sc_channel.
  13. Looks like a problem with MSYS installation. mingw-make works for me, so you can try without msys. Personally I would advice to use Visual Studio on Windows, it is more stable than ported gnu tools.
  14. As I remember, sc_fifo does not have that. But you can create a derived class from sc_fifo with a method to pick value w/o modifying data pointers: something like: T pick() {..}
  15. Thank you! I think we need something like that to be bundled with reference SystemC implementation.
  16. Hi, According to http://accellera.org/activities/working-groups/systemc-verification : The UVM-SystemC Library was released in November 2015 as a public review release. But there is no download link anywhere on accellera portal. Where can I get public release?
  17. In SystemC 2.3.1 it is in sc_boost namespace: ref.hpp: namespace sc_boost { template<class T> class reference_wrapper
  18. Thanks Philipp, I think it may work actually. Will reply back when I test it.
  19. yes, sc_vector is a solution similar to port pointer. You will still have hanging empty sc_vectors, the same as with null pointers. But yes, sc_vectors and pointers are possible solutions. Unfortunately, sc_vectors are not yet supported by SystemC synthesis tools. At least by those that I've tried.
  20. What kind of issue do you have with calling sc_time_stamp() from custom type?
  21. Hello, I'm working on reusable primitives for synthesizable SystemC (like bus transactors, FIFOs, arithmetic units). Sometimes I need to make some ports optional, for example "number of items" signal in FIFO: struct async_fifo: public sc_module { ... sc_out <sc_uint<BITS_FIFO_DEPTH> > num_items; // optional port What is the best known method to do this? Macros do not work, because they do not allow to make instances with different configurations: #ifdef EN_NUM_ITEMS sc_out <sc_uint<BITS_FIFO_DEPTH> > num_items; // if EN_NUM_ITEMS is defined, all instances will have this port Probably someone has an efficient solution using template specialization? I have not figured it out how to do it without a lot of copy-paste code in specializations. The solution I currently use is the dynamic allocation of ports in constructors, depending on template parameters: sc_out <sc_uint<BITS_FIFO_DEPTH> > *num_items; // pointer to port SC_CTOR(async_fifo) { if (en_num_items) num_items = new sc_out<sc_uint<BITS_FIFO_DEPTH> > ("num_items"); else num_items = NULL; } The drawback is that you will always have those null pointers shown in IDE auto-completion assistance.
  22. Transaction level modeling methodology is designed to decrease number of required context switches. You can check TLM-2.0 tutorials.
×
×
  • Create New...