katang Posted June 14, 2017 Report Share Posted June 14, 2017 What is illegal in what I am trying to do? #include "systemc.h" SC_MODULE (BIT_ADDER) { SC_CTOR (BIT_ADDER) { SC_METHOD (process); } void process(); }; class testbench: sc_core::sc_module { public: testbench(sc_core::sc_module_name nm); virtual void test(void) = 0; }; class testbench_adder: public testbench, BIT_ADDER { public: testbench_adder(sc_core::sc_module_name nm); void test(); }; void BIT_ADDER::process() {} SC_HAS_PROCESS(testbench); testbench::testbench(sc_core::sc_module_name nm) : sc_core::sc_module(nm) {} SC_HAS_PROCESS(testbench_adder); testbench_adder::testbench_adder(sc_core::sc_module_name nm) : testbench::testbench(nm), BIT_ADDER("UUT") { SC_THREAD(test); } void testbench_adder::test() { } Quote Link to comment Share on other sites More sharing options...
Roman Popov Posted June 14, 2017 Report Share Posted June 14, 2017 No, multiple inheritance is not supported in this case Here is quote from IEEE 1666-2011 Quote NOTE 2—Since the classes having sc_object as a direct base class (that is, sc_module, sc_port, sc_export, and sc_prim_channel) have class sc_object as a non-virtual base class, any class derived from these classes can have at most one direct base class derived from class sc_object. In other words, multiple inheritance from the classes derived from class sc_object is not permitted. So you have two options: Use composition instead of inheritance : in SystemC case this means you need to instantiate modules and bind their ports In some cases you can put some sc_objects in pure C++ classes (not sc_modules). This technique is commonly used for "port bundles". For example: struct clock_reset_if { sc_in_clk clk{"clk"}; sc_in<bool> rstn{"rstn"}; } struct some_module: sc_module, clock_reset_if { // ... } Unfortunately this approach does not work with SC_METHOD/SC_THREAD macros. But I think it should work with sc_spawn. Philipp A Hartmann and SiGa 2 Quote Link to comment Share on other sites More sharing options...
maehne Posted June 16, 2017 Report Share Posted June 16, 2017 Roman is right with his statements and suggested solutions. However, you should also reconsider the structure of your test bench. A test bench should primarily interact with the DUT through its public interface. Therefore, composition is the right choice, i.e., instantiate your BIT_ADDER inside your test bench module as a member variable. Then, bind its ports to signals and drive/monitor them from SC_METHODs/SC_THREADs. This setup resembles test benches in VHDL. You may still use single inheritance in this case to overload certain functions. However, you should pay attention that only one sc_module_name object gets constructed during the construction of you class, e.g., by taking it as a const reference (see clause 5.3 in IEEE Std 1666-2011). You may also instantiate the test bench module (or separate stimuli/monitor modules) and the DUT on the same hierarchical level from within sc_main() and then connect them via channels. Quote Link to comment Share on other sites More sharing options...
SiGa Posted October 16, 2019 Report Share Posted October 16, 2019 On 6/14/2017 at 6:33 PM, Roman Popov said: In some cases you can put some sc_objects in pure C++ classes (not sc_modules). This technique is commonly used for "port bundles". For example: struct clock_reset_if { sc_in_clk clk{"clk"}; sc_in<bool> rstn{"rstn"}; } struct some_module: sc_module, clock_reset_if { // ... } I'm trying to use this approach for my problem. I created a header with two classes as you mentioned. Then I inherit them into the module where I want the "port bundle" to be. I get a lot of these Warnings: "Warning: (W505) object already exists: monitor.R_OP_MODE. Latter declaration will be renamed to monitor.R_OP_MODE_0 In file: c:\xx\xx\xx\xx\systemc-2.3.3\src\sysc\kernel\sc_object_manager.cpp:153" And one error, which probably causes the abortion. Error: (E109) complete binding failed: port not bound: port 'monitor.T_PRESET_MANUAL' (sc_inout) In file: c:\xx\xx\xx\xx\systemc-2.3.3\src\sysc\communication\sc_port.cpp:235 A minimal example is provided at the of my post with zipped source files. //interface.h #pragma once #include <systemc.h> // Class is meant to be inherited from, to have all Interface inputs struct if_inputs { // port declaration sc_inout<sc_uint<4> > R_OP_MODE{ "R_OP_MODE" }; sc_inout<sc_uint<8> > R_PRESET_MANUAL{ "R_PRESET_MANUAL" }; }; // Class is meant to be inherited from, to have all Interface outputs struct if_outputs { // port declaration sc_inout<sc_uint<2> > T_BIT{ "T_BIT" }; sc_inout<sc_uint<4> > T_OP_MODE{ "T_OP_MODE" }; sc_inout<sc_uint<8> > T_PRESET_MANUAL{ "T_PRESET_MANUAL" }; }; //A.h #pragma once #include <systemc.h> #include "interface.h" class A : public sc_module, public if_inputs, public if_outputs { public: public: SC_CTOR(A) { //SC_METHOD(T01_SBIT_sig_forward); //sensitive << T01_SBIT_in; } }; //B.h #pragma once #define SC_INCLUDE_DYNAMIC_PROCESSES //for sc_spawn #include <systemc.h> #include "interface.h" #include <functional> class B : public sc_module, public if_inputs, public if_outputs { public: // port declaration sc_in<bool> POWER_ON{ "POWER_ON" }; // process functionality void B::some_process(); private: std::vector<sc_time> timings{sc_time(3,SC_SEC), sc_time(6,SC_SEC), sc_time(9,SC_SEC) }; public: //constructor SC_CTOR(B) { //register processes SC_THREAD(some_process); sensitive << POWER_ON; } }; //stimulator.h #pragma once #define SC_INCLUDE_DYNAMIC_PROCESSES //for sc_spawn #include <systemc.h> #include "interface.h" struct if_inputs; struct if_outputs; class stimulator: public sc_module, public if_inputs, public if_outputs { public: sc_out<bool> POWER_ON; //processes void stimulator::stimulus_generator(); public: // constructor SC_CTOR(stimulator): // name ports for easier debugging POWER_ON("POWER_ON") { // Register processes SC_THREAD(stimulus_generator); // waits on fifo write_event } }; // monitor.h #pragma once #define SC_INCLUDE_DYNAMIC_PROCESSES //for sc_spawn #include <systemc.h> #include"interface.h" class monitor : public sc_module, public if_inputs, public if_outputs { public: //// port declaration sc_in<bool> POWER_ON; public: class sim: public if_inputs, public if_outputs { }sim; class stub : public if_inputs, public if_outputs { }stub; public: SC_HAS_PROCESS(monitor); //// constructor monitor::monitor(sc_module_name name_); }; //stimulator.cpp #include "stimulator.h" void stimulator::stimulus_generator() { POWER_ON = true; } //source file: blackbox.cpp #include "B.h" void B::some_process() { } //monitor.cpp #include "monitor.h" monitor::monitor(sc_module_name name_) :sc_module(name_) { } // main.cpp #pragma once #include <systemc.h> #include "B.h" #include "A.h" #include "stimulator.h" #include "monitor.h" int sc_main(int argc, char** argv) { // Set some SystemC time parameters (maybe not necessarily needed). sc_set_time_resolution(1.0, SC_US); // signal declaration sc_signal<bool > POWER_ON{ "POWER_ON" }; sc_signal<sc_uint<2>, SC_MANY_WRITERS> T_BIT_sim{"T_BIT_sim"}; sc_signal<sc_uint<2>, SC_MANY_WRITERS> T_BIT_stub{"T_BIT_stub"}; sc_signal<sc_uint<4>, SC_MANY_WRITERS> T_OP_MODE_sim{ "T_OP_MODE_sim" }; sc_signal<sc_uint<4>, SC_MANY_WRITERS> T_OP_MODE_stub{ "T_OP_MODE_stub" }; sc_signal<sc_uint<8>, SC_MANY_WRITERS> T_PRESET_MANUAL_sim{ "T_PRESET_MANUAL_sim" }; sc_signal<sc_uint<8>, SC_MANY_WRITERS> T_PRESET_MANUAL_stub{ "T_PRESET_MANUAL_stub" }; sc_signal<sc_uint<4>, SC_MANY_WRITERS> R_OP_MODE_sim{ "R_OP_MODE_sim" }; sc_signal<sc_uint<4>, SC_MANY_WRITERS> R_OP_MODE_stub{ "R_OP_MODE_stub" }; sc_signal<sc_uint<8>, SC_MANY_WRITERS> R_PRESET_MANUAL_sim{ "R_PRESET_MANUAL_sim" }; sc_signal<sc_uint<8>, SC_MANY_WRITERS> R_PRESET_MANUAL_stub{ "R_PRESET_MANUAL_stub" }; B sim("sim"); sim.POWER_ON(POWER_ON); sim.T_BIT(T_BIT_sim); sim.T_OP_MODE(T_OP_MODE_sim); sim.T_PRESET_MANUAL(T_PRESET_MANUAL_sim); sim.R_OP_MODE(R_OP_MODE_sim); sim.R_PRESET_MANUAL(R_PRESET_MANUAL_sim); A stub("stub"); stub.T_BIT(T_BIT_stub); stub.T_OP_MODE(T_OP_MODE_stub); stub.T_PRESET_MANUAL(T_PRESET_MANUAL_stub); stub.R_OP_MODE(R_OP_MODE_stub); stub.R_PRESET_MANUAL(R_PRESET_MANUAL_stub); monitor mon("monitor"); mon.POWER_ON(POWER_ON); mon.sim.T_BIT(T_BIT_sim); mon.sim.T_OP_MODE(T_OP_MODE_sim); mon.sim.T_PRESET_MANUAL(T_PRESET_MANUAL_sim); mon.sim.R_OP_MODE(R_OP_MODE_sim); mon.sim.R_PRESET_MANUAL(R_PRESET_MANUAL_sim); mon.stub.T_BIT(T_BIT_stub); mon.stub.T_OP_MODE(T_OP_MODE_stub); mon.stub.T_PRESET_MANUAL(T_PRESET_MANUAL_stub); mon.stub.R_OP_MODE(R_OP_MODE_stub); mon.stub.R_PRESET_MANUAL(R_PRESET_MANUAL_stub); sc_start(); return 0; } MinExample.zip Quote Link to comment Share on other sites More sharing options...
Philipp A Hartmann Posted October 16, 2019 Report Share Posted October 16, 2019 You have multiple instances of the "bundles" in your monitor class: inherited directly as additional members in the nested classes sim and stub To avoid the name clashes, you can make sim and stub modules themselves via: struct sim : sc_module , if_inputs, if_outputs { SC_CTOR(sim) {} } sim { "sim" }; SiGa 1 Quote Link to comment Share on other sites More sharing options...
Roman Popov Posted October 16, 2019 Report Share Posted October 16, 2019 Quote I'm trying to use this approach for my problem. In general avoid using multiple inheritance for aggregation. It is possible, but has many drawbacks and no major benefits. Now I regret that I've written original post, but at that time I had no enough experience myself. Now, if we read any object oriented design book, we will learn that inheritance usually means "is-a" relation ship, and "has-a" relation ship is expressed by composition. Translating into HW modeling : what we want to express is that "some_module has port bundles", and not "some_module is port bundles". We can still use single inheritance in limited cases, for example if all modules in design have clock and reset, we can have a common base class like class clocked_module : public sc_module Back to your example. I recommend to convert your port bundles into modules: struct if_inputs : sc_module { sc_inout<sc_uint<4>> SC_NAMED(R_OP_MODE); sc_inout<sc_uint<8>> SC_NAMED(R_PRESET_MANUAL); if_inputs(sc_module_name){} }; struct if_outputs : sc_module { sc_inout<sc_uint<2>> SC_NAMED(T_BIT); sc_inout<sc_uint<4>> SC_NAMED(T_OP_MODE); sc_inout<sc_uint<8>> SC_NAMED(T_PRESET_MANUAL); if_outputs(sc_module_name){} }; And now you can aggregate any number of them inside monitor. Even have a vector of port bundles: class monitor : public sc_module { public: if_inputs SC_NAMED(sim_inputs); if_outputs SC_NAMED(sim_outputs); if_inputs SC_NAMED(stub_inputs); if_outputs SC_NAMED(stub_outputs); sc_vector<if_inputs> SC_NAMED(inputs_vector, 3); monitor(sc_module_name name_); private : // implementation details }; SiGa 1 Quote Link to comment Share on other sites More sharing options...
SiGa Posted October 22, 2019 Report Share Posted October 22, 2019 On 10/16/2019 at 3:11 PM, Philipp A Hartmann said: You have multiple instances of the "bundles" in your monitor class: inherited directly as additional members in the nested classes sim and stub To avoid the name clashes, you can make sim and stub modules themselves via: struct sim : sc_module , if_inputs, if_outputs { SC_CTOR(sim) {} } sim { "sim" }; Thank you Philipp, this solved my runtime errors. I also removed if_inputs/-outputs as parents for the monitor class, since I nested them into stub and sim. class monitor : public sc_module { ... }; _________________________________ On 10/16/2019 at 3:34 PM, Roman Popov said: In general avoid using multiple inheritance for aggregation. It is possible, but has many drawbacks and no major benefits. Now I regret that I've written original post, but at that time I had no enough experience myself. Now, if we read any object oriented design book, we will learn that inheritance usually means "is-a" relation ship, and "has-a" relation ship is expressed by composition. Translating into HW modeling : what we want to express is that "some_module has port bundles", and not "some_module is port bundles". We can still use single inheritance in limited cases, for example if all modules in design have clock and reset, we can have a common base class like class clocked_module : public sc_module Back to your example. I recommend to convert your port bundles into modules: struct if_inputs : sc_module { sc_inout<sc_uint<4>> SC_NAMED(R_OP_MODE); sc_inout<sc_uint<8>> SC_NAMED(R_PRESET_MANUAL); if_inputs(sc_module_name){} }; struct if_outputs : sc_module { sc_inout<sc_uint<2>> SC_NAMED(T_BIT); sc_inout<sc_uint<4>> SC_NAMED(T_OP_MODE); sc_inout<sc_uint<8>> SC_NAMED(T_PRESET_MANUAL); if_outputs(sc_module_name){} }; And now you can aggregate any number of them inside monitor. Even have a vector of port bundles: class monitor : public sc_module { public: if_inputs SC_NAMED(sim_inputs); if_outputs SC_NAMED(sim_outputs); if_inputs SC_NAMED(stub_inputs); if_outputs SC_NAMED(stub_outputs); sc_vector<if_inputs> SC_NAMED(inputs_vector, 3); monitor(sc_module_name name_); private : // implementation details }; Thank you for the explanation and the provided examples. Now I know two ways of solving my problem. Your solution seems to have lesse overhead, or is the same with Phlipp's solution? Philipp's way lets me have inputs and outputs in the same scope when I connect signals to the ports in the main.cpp. Which fits my modeling style more. Is there a way to also archieve this with your solution? Without changing if_inputs/-outputs? Quote Link to comment Share on other sites More sharing options...
Roman Popov Posted October 22, 2019 Report Share Posted October 22, 2019 Quote Philipp's way lets me have inputs and outputs in the same scope when I connect signals to the ports in the main.cpp. Which fits my modeling style more. Is there a way to also archieve this with your solution? Without changing if_inputs/-outputs? No, if you want to keep all ports in same scope you will need to follow Philipp's suggestion. SiGa 1 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.