Roman Popov Posted April 5, 2016 Report Share Posted April 5, 2016 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(); } } }; maehne 1 Quote Link to comment Share on other sites More sharing options...
Roman Popov Posted April 10, 2016 Author Report Share Posted April 10, 2016 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; } maehne 1 Quote Link to comment Share on other sites More sharing options...
Roman Popov Posted April 10, 2016 Author Report Share Posted April 10, 2016 One more thing to consider is positional port binding using initializer list. While I never use this feature, I think it can be implemented in some better way. Looks like there is a limitation of maximum 64 ports with current sc_module : void operator () ( const sc_bind_proxy& p001, const sc_bind_proxy& p002 = SC_BIND_PROXY_NIL, const sc_bind_proxy& p003 = SC_BIND_PROXY_NIL, const sc_bind_proxy& p062 = SC_BIND_PROXY_NIL, ... const sc_bind_proxy& p063 = SC_BIND_PROXY_NIL, const sc_bind_proxy& p064 = SC_BIND_PROXY_NIL ); }; maehne 1 Quote Link to comment Share on other sites More sharing options...
Roman Popov Posted April 13, 2016 Author Report Share Posted April 13, 2016 Some syntax to create methods/threads out of constructor body would be helpful too. For example by creating classes sc_thread and sc_method. imagine something like SC_MODULE (foo) { SC_CTOR(foo); // sc_method ( sensitivity_list , process_handle ) sc_method sum_method ( {a,b,c} , [&]() { sum = a + b + c; } }; void diff_method_body(); sc_method diff_method ( {x,y} , diff_method_body ); }; void foo::diff_method_body() { diff = x - y; } maehne 1 Quote Link to comment Share on other sites More sharing options...
Roman Popov Posted April 17, 2016 Author Report Share Posted April 17, 2016 One more powerful feature of Verilog are implicit signals and methods. Consider following example: logic clk; logic [7:0] addr; logic write_en; logic slave0_irq; logic slave1_irq; master master0 ( .clk(clk), .addr(addr), .write_en(write_en), .interrupt_vec( {slave1_irq, slave0_irq} ) ); slave slave0 ( .clk(clk), .addr(addr[6:0]), .write_en(write_en && addr[7] == 0 ), .interrupt(slave0_irq) ); slave slave1 ( .clk(clk), .addr(addr[6:0]), .write_en(write_en && addr[7] == 1 ), .interrupt(slave1_irq) ); In Verilog I can bind port to signal sub-range without explicitly defining additional signal and creating a method to extract sub-range: Verilog: .addr(addr[6:0]), SystemC: sc_signal<sc_bv<7> > subaddr{"subsignal"}; ... void extract_subrange_method() { subaddr = addr.read().range(6,0); } ... SC_METHOD(extract_subrange_method); sensitive << addr; ... slave0.addr(subaddr); About 7 LOC in SystemC vs 1 LOC in Verilog. Verilog allows to merge multiple signals into one: .interrupt_vec( {slave1_irq, slave0_irq} ) Or even more complex expressions : .write_en(write_en && addr[7] == 1 ), So if I rewrite whole module from Verilog to SystemC I will get about 150-200 LOC vs 35 LOC in original Verilog file. SystemC desperately needs similar syntax if it wants to grow as HDL. Mixing Verilog and SystemC is not an option: in general I have HLS-style and RTL-style code in same module. So we either need an HLS for Verilog, or facelift for SystemC. It feels like it is possible to implement such type of binding at library level, without creating additional "SystemC preporcessor". Because we bind sc_ports to sc_signals (not to primitive types (char, int)) it is possible to improve those classes to support this type of syntax. For example we can apply expression templates over sc_signals: https://en.wikipedia.org/wiki/Expression_templates So expression like this: write_en && addr[7] == 1 over sc_signals will return some class sc_expression that will contain both: recursive function to compute expression list of sc_signals that will go into sensitivity list Next, during port binding create anonymous sc_signal with the same type as port. And spawn a method that will assign this signal a value computed by expression template. maehne 1 Quote Link to comment Share on other sites More sharing options...
Roman Popov Posted May 8, 2016 Author Report Share Posted May 8, 2016 If we combine expression templates and in-place initialization, enhanced C++11 syntax can look something like that: SC_MODULE(demo_mod) { sc_in<int> a_in{"a_in"}; // second optional parameter is assignment expression sc_out<sc_int<8>> b_out{"b_out", a_in + c_sig}; // constant zero output sc_out<int> zero_out{"zero_out", 0}; sc_signal<sc_uint<4>> c_sig{"c_sig"}; // some bus port amba::apb_slave apb_in{"apb_in"}; // sencond optional paramteter to sc_module_name is binding function some_module inst_name {{"inst_name", [&]() { inst_name.in0(a_in); inst_name.apb_in(apb_in); // bus binding inst_name.in1(10); // bind to constant inst_name.out0(); // unconnected by design }}}; sc_signal<sc_uint<8>> d_sig{"d_sig"}; SC_CTOR(demo_mod) { // assignment d_sig.assign( (c_sig , c_sig) - 10 ); SC_THREAD(test_thread); } sc_signal<sc_uint<8>> e_sig{"e_sig"}; void test_thread() { int var = 12; // wait for expression wait( c_sig[0] && (a_in == 12) ); // evaluates expression e_sig = a_in + b_out.range(3,0) + d_sig + 12; sc_stop(); } }; maehne 1 Quote Link to comment Share on other sites More sharing options...
dakupoto Posted May 9, 2016 Report Share Posted May 9, 2016 If we combine expression templates and in-place initialization, enhanced C++11 syntax can look something like that: SC_MODULE(demo_mod) { sc_in<int> a_in{"a_in"}; // second optional parameter is assignment expression sc_out<sc_int<8>> b_out{"b_out", a_in + c_sig}; // constant zero output sc_out<int> zero_out{"zero_out", 0}; sc_signal<sc_uint<4>> c_sig{"c_sig"}; // some bus port amba::apb_slave apb_in{"apb_in"}; // sencond optional paramteter to sc_module_name is binding function some_module inst_name {{"inst_name", [&]() { inst_name.in0(a_in); inst_name.apb_in(apb_in); // bus binding inst_name.in1(10); // bind to constant inst_name.out0(); // unconnected by design }}}; sc_signal<sc_uint<8>> d_sig{"d_sig"}; SC_CTOR(demo_mod) { // assignment d_sig.assign( (c_sig , c_sig) - 10 ); SC_THREAD(test_thread); } sc_signal<sc_uint<8>> e_sig{"e_sig"}; void test_thread() { int var = 12; // wait for expression wait( c_sig[0] && (a_in == 12) ); // evaluates expression e_sig = a_in + b_out.range(3,0) + d_sig + 12; sc_stop(); } }; Sir, Maybe you should create your own proof-pf-concept implementation that includes all these advanced features that you mention above. You could then sell it commercially. Maybe you should stop responding to your own posts -- justa thought. Quote Link to comment Share on other sites More sharing options...
maehne Posted May 9, 2016 Report Share Posted May 9, 2016 Dear Roman, contrary to the previous poster, I would like to encourage you to keep posting your proposals for improving the syntax of SystemC! They come very timely. The IEEE Std 1666-2011 will need to get revised in the coming years to not become obsolete. The current standard is still based on C++'03 and the next version will need to get aligned to C++'14 or the then current C++ standard version. This forum is the right place for regular SystemC users to expose their ideas about what they would like to see in a revised standards. Members of the SystemC Language Working Group are reading and contributing to the Accellera Forums on a regular basis and are thus aware of your proposals -- even if they don't provide feedback for the moment. Personally, I think that your proposals are a good starting point for thinking further how SystermC users can tear most benefits from the possibilities of the new C++ standards to simplify the code of their models. Improvements to the SystemC syntax, which don't jeopardize backwards compatibility, will be more easy to integrate than proposals, which are not compatible to the current standard. The latter probably need to be very convincing in terms of usability and productivity improvement to get considered in a new revision of SystemC. Personally, I would also try to avoid as much as possible the introduction of any new preprocessor macros in SystemC. So, please keep posting! I hope that also other Forum members will provide feedback in the future. Best regards, Torsten Maehne Quote Link to comment Share on other sites More sharing options...
dakupoto Posted May 11, 2016 Report Share Posted May 11, 2016 Dear Roman, contrary to the previous poster, I would like to encourage you to keep posting your proposals for improving the syntax of SystemC! They come very timely. The IEEE Std 1666-2011 will need to get revised in the coming years to not become obsolete. The current standard is still based on C++'03 and the next version will need to get aligned to C++'14 or the then current C++ standard version. This forum is the right place for regular SystemC users to expose their ideas about what they would like to see in a revised standards. Members of the SystemC Language Working Group are reading and contributing to the Accellera Forums on a regular basis and are thus aware of your proposals -- even if they don't provide feedback for the moment. Personally, I think that your proposals are a good starting point for thinking further how SystermC users can tear most benefits from the possibilities of the new C++ standards to simplify the code of their models. Improvements to the SystemC syntax, which don't jeopardize backwards compatibility, will be more easy to integrate than proposals, which are not compatible to the current standard. The latter probably need to be very convincing in terms of usability and productivity improvement to get considered in a new revision of SystemC. Personally, I would also try to avoid as much as possible the introduction of any new preprocessor macros in SystemC. So, please keep posting! I hope that also other Forum members will provide feedback in the future. Best regards, Torsten Maehne Sir, While there is nothing wrong about including ever more advanced C++ language features into SystemC, one has to ponder as to how these new language features would better facilitate the analysis of a given design problem. In particular, one has to examine how and why the Google search engine has maintained its absolute stranglehold, while Yahoo and Bing have fallen by the wayside. All of the Google core modules have been written in plain ANSI C. As it is, C++ is a very complicated language compared to its mother language C, with inheritance, multiple inheritance, function overriding, operator overloading, pure virtual functions and templates. The only feature complicated about C is pointer arithmetic, which is carried over to C++. In addition, C++ adds its own complexity. As an example, consider the fact that a few years ago intel added 400 extra pins to its 2 core processors, raising the total pin count from 755 to 1155. However, from personal experience I know that these 400 extra pins do not in any way improve the performance of any PC, but rather makes motherboard design more complicated/ difficult and error-prone and prototype debugging/testing a major headache. Albert Einstein once said something like 'make it simple but not more simpler', implying that everything should have just the right amount of complexity built in, but no less or more. Quote Link to comment Share on other sites More sharing options...
Roman Popov Posted May 11, 2016 Author Report Share Posted May 11, 2016 Maybe you should create your own proof-pf-concept implementation that includes all these advanced features that you mention above This is my plan. You could then sell it commercially. My plan is opposite: if this sort of syntax will be helpful for users, commercial vendors will probably support it in existing systemc synthesis tools. Albert Einstein once said something like 'make it simple but not more simpler', implying that everything should have just the right amount of complexity built in, but no less or more. Speaking about SystemC "language" complexity: this is indeed the case with current SystemC. Because of that most HW designers prefer Verilog/SystemVerilog. But features I've presented are about reducing SystemC syntax complexity, not about further complication. So code will be more compact, less verbose and error-prone. Personally I find one good thing about HW design in SystemC: If I will lose my job in semiconductor industry, I can find another one as C++ programmer Something I couldn't do if I were a SystemVerilog programmer. maehne 1 Quote Link to comment Share on other sites More sharing options...
dakupoto Posted May 14, 2016 Report Share Posted May 14, 2016 This is my plan. My plan is opposite: if this sort of syntax will be helpful for users, commercial vendors will probably support it in existing systemc synthesis tools. Speaking about SystemC "language" complexity: this is indeed the case with current SystemC. Because of that most HW designers prefer Verilog/SystemVerilog. But features I've presented are about reducing SystemC syntax complexity, not about further complication. So code will be more compact, less verbose and error-prone. Personally I find one good thing about HW design in SystemC: If I will lose my job in semiconductor industry, I can find another one as C++ programmer Something I couldn't do if I were a SystemVerilog programmer. SystemC's predecessor is SpecC, cones with its own compiler and freely downloadable. Syntax is very much like the plain C language without any of the complexities of the C++ language. Why SystemC flourished to become an industry standard, and SpeC remains mostly as an academic tool, is a long story. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.