SiGa Posted September 3, 2019 Report Share Posted September 3, 2019 I have an SC_MODULE that contains two types(probably multiple types in the future) of sc_out ports. I want to store a reference(or pointer) of the port in a std::map, so that I can later get the right port through lookup of strings and access the write method of it. Following post helped me understand the topic better but for me it is still unclear how I can achieve my goal. I don't understand how I should cast my stored reference. Small example for showing how I want to use it. #pragma once #include <systemc.h> #include <map> //typedef std::map<std::string, sc_interface*> Map0; //typedef std::map<std::string, sc_object*> Map0; typedef std::map<std::string, (????)*> Map0; // what type should I use since sc_out<T> varies on type T class stimulator: public sc_module { public: sc_out<bool> POWER_ON; sc_out<sc_uint<2>> T01_SBIT_mil_stub; private: Map0 dict; public: void stimulator::stimulus_generator() { std::string key0; for(int i=0; i<=1; i++) { if(i==0) key0 = "VOLTAGE"; else key0 = "T01_SBIT_mil_stub"; dict::iterator it0 = dict.find(key0); if (it0 == dict.end()) cout << "Map lookup key not found." << endl; // How to cast it? Type Erasure? if(i==0) it0->second->write(true); //write method not available else it0->second->write(1); //write method not available } } public: SC_CTOR(stimulator): POWER_ON("POWER_ON"), T01_SBIT_mil_stub("T01_SBIT_mil_stub") { // if type of map is sc_object* use get_parent() instead of get_interface() dict.insert( std::make_pair("VOLTAGE", POWER_ON.get_interface()) ); dict.insert( std::make_pair("T01_SBIT_mil_stub", T01_SBIT_mil_stub.get_interface()) ); SC_THREAD(stimulus_generator); // runs one time at creation, which is sufficient to demonstrate } } Is an sc_object* the best way to do it? If yes how do I cast it back to the right sc_out<T>? I know that I could solve my problem with a different approach, like defining enums and each enum indicates a port and thus I know which port I should write to. But that would involve more lines of code that is not really flexible. I prefer the generic way and would like to understand the SystemC framework better. Thanks for any help or guidance in advance 🙂 Quote Link to comment Share on other sites More sharing options...
Eyck Posted September 3, 2019 Report Share Posted September 3, 2019 Well, this topic is not easy to solve. In C++ each template instantiation (like sc_in<bool>) is a separate class in the class hierachy. The common base class is sc_port_base and this is in this context more or less useless. Actually there I see 2 options: You store a sc_port_base pointer in your map and upon each write you check for the typeid of the specific template instance and down-cast it using dynamic_cast. This is inflexible and needs additional coding if you want to use new type. You store a writer function in your map which knows how to translate a generic value (like int or double) to the particular value. This might by a lambda which captures the port reference and therefore 'knows' hwo to write to this port. But in this case you would loose type safety as you have to store a generic function unless you can use std::variant. So your map would have to be declared as typedef std::map<std::string, std::function<void(unsigned)> Map0 or (C++17): typedef std::map<std::string, std::function<void(std::variant<bool, sc_dt::sc_uint<2>>> Map0 I personally would go for option 2 as it is simpler and more flexible... HTH SiGa 1 Quote Link to comment Share on other sites More sharing options...
SiGa Posted September 4, 2019 Author Report Share Posted September 4, 2019 Hello Eyck, thank you for the reply. 19 hours ago, Eyck said: You store a sc_port_base pointer in your map and upon each write you check for the typeid of the specific template instance and down-cast it using dynamic_cast. This is inflexible and needs additional coding if you want to use new type. I have read that dynamic_cast will cause a perfomance penalty due to runtime checking things. Since I will be doing this a lot of times I should probably avoid this solution. 19 hours ago, Eyck said: You store a writer function in your map which knows how to translate a generic value (like int or double) to the particular value. This might by a lambda which captures the port reference and therefore 'knows' hwo to write to this port. But in this case you would loose type safety as you have to store a generic function unless you can use std::variant. So your map would have to be declared as This seems like a good solution. In the end I only need to write a function for each type of port instead of a function for each port. With this approach I run into a different problem. I tried using c++17 through installing VisualStudio2017, but it did not accept the /std::c++17 build parameter. I will need additional time googling it up and will eventually get there. For now my solution with c++14 would look like this: #pragma once #define SC_INCLUDE_DYNAMIC_PROCESSES //for sc_spawn #include <systemc.h> #include <map> typedef std::map < std::string, std::function<void(sc_time,bool,sc_out<bool>)>> Map0; class stimulator: public sc_module { public: sc_out<bool> POWER_ON; sc_out<sc_uint<2>> T01_SBIT_mil_stub; private: Map0 dict; void delayed_stimulus_bool(sc_time delay, bool value, sc_out<bool> *port) { wait(delay); port->write(value); } void delayed_stimulus_uint2(sc_time delay, sc_uint<2> value, sc_out<sc_uint<2>> *port) { wait(delay); port->write(value); } public: void stimulator::stimulus_generator() { std::string key0; for(int i=0; i<=1; i++) { if(i==0) key0 = "VOLTAGE"; else key0 = "T01_SBIT_mil_stub"; dict::iterator it0 = dict.find(key0); if (it0 == dict.end()) cout << "Map lookup key not found." << endl; if(i==0) sc_spawn( sc_bind(it0->second, this, true, value, &POWER_ON) ); else sc_spawn( sc_bind(it0->second, this, 1, value, &T01_SBIT_mil_stub) ); } } public: SC_CTOR(stimulator): POWER_ON("POWER_ON"), T01_SBIT_mil_stub("T01_SBIT_mil_stub") { dict.insert( std::make_pair("VOLTAGE", this->delayed_stimulus_bool) ); dict.insert( std::make_pair("T01_SBIT_mil_stub", this->delayed_stimulus_uint2) ); // can not add this function pointer because it's type is different SC_THREAD(stimulus_generator); // runs one time at creation, which is sufficient to demonstrate } } How can I add two different method pointers into the same list without using std::variant? Quote Link to comment Share on other sites More sharing options...
Eyck Posted September 6, 2019 Report Share Posted September 6, 2019 boost::variant would be an option or you use a union. In the latter case you loose the type safety... SiGa 1 Quote Link to comment Share on other sites More sharing options...
SiGa Posted September 9, 2019 Author Report Share Posted September 9, 2019 Thank you for the suggestions. In the end I upgraded my project to c++17 and stored lambda functions with a variant as parameter. When I need to create a delayed stimulus I spawn a SC_THREAD function that takes the function pointer, a delay and a variant as parameter. In the spawned function I wait for the delay and then call the function pointer and pass the variant as argument. #pragma once #include <systemc.h> #include <map> typedef std::variant< bool, unsigned int > value_types; typedef std::function< void(value_types) > func_ptr_type; typedef std::map <std::string, func_ptr_type> Map0; class stimulator: public sc_module { public: sc_out<bool> POWER_ON; sc_out<unsigned int> T01_SBIT_mil_stub; private: Map0 dict; public: void stimulator::stimulus_generator() { std::string key0; for(int i=0; i<=1; i++) { if(i==0) key0 = "VOLTAGE"; else key0 = "T01_SBIT_mil_stub"; dict::iterator it0 = dict.find(key0); if (it0 == dict.end()) cout << "Map lookup key not found." << endl; func_ptr_type func = it0->second; value_types argument; if(i==0) argument = true; else argument = 2; sc_time delay = sc_time(10 ,SC_MS); auto temp = sc_bind(&stimulator::delayed_execution, this, func, argument, delay); sc_spawn( temp ); } } private: void stimulator::delayed_execution(func_ptr_type func, value_types value, sc_time delay) { cout << "stimulator::delayed_stimulus" << endl; wait(delay); func(value); } public: SC_CTOR(stimulator): POWER_ON("POWER_ON"), T01_SBIT_mil_stub("T01_SBIT_mil_stub") { dict["VOLTAGE"] = [this](value_types val) { POWER_ON.write(std::get<bool>(val)); }; dict["T01_SBIT_mil_stub"] = [this](value_types val) { T01_SBIT_mil_stub.write(std::get<unsigned int>(val)); }; // runs one time at creation, which is sufficient to demonstrate SC_THREAD(stimulus_generator); } } Thank you fo the help. 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.