Commit | Line | Data |
---|---|---|
86530b38 AT |
1 | /*****************************************************************************\r |
2 | \r | |
3 | The following code is derived, directly or indirectly, from the SystemC\r | |
4 | source code Copyright (c) 1996-2004 by all Contributors.\r | |
5 | All Rights reserved.\r | |
6 | \r | |
7 | The contents of this file are subject to the restrictions and limitations\r | |
8 | set forth in the SystemC Open Source License Version 2.4 (the "License");\r | |
9 | You may not use this file except in compliance with such restrictions and\r | |
10 | limitations. You may obtain instructions on how to receive a copy of the\r | |
11 | License at http://www.systemc.org/. Software distributed by Contributors\r | |
12 | under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF\r | |
13 | ANY KIND, either express or implied. See the License for the specific\r | |
14 | language governing rights and limitations under the License.\r | |
15 | \r | |
16 | *****************************************************************************/\r | |
17 | \r | |
18 | #ifndef _TLM_INITIATOR_PORT_H_\r | |
19 | #define _TLM_INITIATOR_PORT_H_\r | |
20 | \r | |
21 | /*------------------------------------------------------------------------------\r | |
22 | * Includes\r | |
23 | *----------------------------------------------------------------------------*/\r | |
24 | #include <vector>\r | |
25 | \r | |
26 | #include "systemc.h"\r | |
27 | \r | |
28 | #include "tlm_ports/tlm_initiator_port_base.h"\r | |
29 | #include "tlm_ports/tlm_target_port.h"\r | |
30 | \r | |
31 | \r | |
32 | //----------------------------------------------------------------------------\r | |
33 | /// Class tlm_initiator_port: port to be instantiated on the initiator side\r | |
34 | /**\r | |
35 | * This class could be used as base class for user defined initiator ports (support of user convenience layer).\r | |
36 | * \n It provides new binding methods definition: \r | |
37 | * - sc_port to sc_export binding must be identified in order to create target_port_list\r | |
38 | * used for port ID propagation through hierarchical binding. \r | |
39 | * - sc_port to sc_port binding creates two initiator ports lists: one regular list (deep port "knows" other\r | |
40 | * initiator ports through a hierarchy) and a reversed list (the port directly bound to the interface\r | |
41 | * "knows" deeper ports through a hierarchy) used to convey target_port list to deeper ports for target port\r | |
42 | * ID propagation.\r | |
43 | * An error detection is also provided: When the same interface is bound two times to a sc_port, SystemC causes \r | |
44 | * the simulation end. This case could append in test platform (dedicated debug and regular port of a target \r | |
45 | * bound to the same router). The specific binding issues a warning message but let the simulation run.\r | |
46 | \r | |
47 | **/\r | |
48 | //----------------------------------------------------------------------------\r | |
49 | template<typename IF,int N = 1>\r | |
50 | class tlm_initiator_port : \r | |
51 | public sc_port<IF,N>,\r | |
52 | public tlm_initiator_port_base {\r | |
53 | \r | |
54 | typedef IF interface_type;\r | |
55 | typedef tlm_target_port<IF> target_port_type;\r | |
56 | typedef tlm_initiator_port<IF,N> initiator_port_type;\r | |
57 | \r | |
58 | typedef tlm_target_port_base target_port_base_type;\r | |
59 | typedef tlm_initiator_port_base initiator_port_base_type;\r | |
60 | \r | |
61 | public:\r | |
62 | \r | |
63 | //--------------\r | |
64 | // Constructor\r | |
65 | //--------------\r | |
66 | tlm_initiator_port(const char * name);\r | |
67 | \r | |
68 | \r | |
69 | //--------------------------------------------------------------------\r | |
70 | /// @name sc_port overridden methods\r | |
71 | /// Need to specialize binding operation to support port propagation in transaction recorders. \r | |
72 | /// Specialization is done for sc_port/sc_port and sc_port/sc_export \r | |
73 | /// Other redefinitions of bindings are just calls to regular bind function\r | |
74 | /// \n Note: This is due to non virtual definition of SystemC bind method\r | |
75 | //--------------------------------------------------------------------\r | |
76 | /// @{\r | |
77 | ///\r | |
78 | //-------------------------------------------------------------------------------\r | |
79 | // Before end of elaboration\r | |
80 | /**\r | |
81 | * Called just before end of elaboration to propagate registered target ports to all the \r | |
82 | * bound initiator ports (using the reversed initiator port list).\r | |
83 | *\r | |
84 | * Remark: sc_port_base::complete_binding should be the best place to do \r | |
85 | * that but this method is private !!\r | |
86 | **/\r | |
87 | //-------------------------------------------------------------------------------\r | |
88 | void before_end_of_elaboration();\r | |
89 | \r | |
90 | //-------------------------------------------------------------------------------\r | |
91 | // End of elaboration\r | |
92 | /**\r | |
93 | * Called at the end of elaboration. Checks target port list: empty target port\r | |
94 | * list is a fatal error as initiator port should be bound at least to one target_port\r | |
95 | **/\r | |
96 | //-------------------------------------------------------------------------------\r | |
97 | void end_of_elaboration();\r | |
98 | \r | |
99 | \r | |
100 | //--------------------------------------------------------------------\r | |
101 | // Special binding between initiator port and target port.\r | |
102 | // (port registration added to the standard sc_port_base::bind())\r | |
103 | //--------------------------------------------------------------------\r | |
104 | \r | |
105 | /// bind(sc_export) overridden with port registration \r | |
106 | void bind(target_port_type& target_port_);\r | |
107 | \r | |
108 | /// Case of the other port uses another interface as template: works only if OTHER_IF derives from IF\r | |
109 | template<typename OTHER_IF>\r | |
110 | void bind(tlm_target_port<OTHER_IF>& target_port_);\r | |
111 | \r | |
112 | \r | |
113 | /// operator() (sc_export) overridden with port registration \r | |
114 | void operator() (target_port_type& target_port_);\r | |
115 | \r | |
116 | /// Case of the other port uses another interface as template: works only if OTHER_IF derives from IF\r | |
117 | template<typename OTHER_IF>\r | |
118 | void operator() (tlm_target_port<OTHER_IF>& target_port_) {\r | |
119 | bind<OTHER_IF>(target_port_);\r | |
120 | }\r | |
121 | \r | |
122 | \r | |
123 | /// bind(sc_port) overridden with port registration \r | |
124 | void bind(sc_port_b<interface_type>& port_);\r | |
125 | \r | |
126 | /// operator() (sc_port) overridden with port registration \r | |
127 | void operator() (sc_port_b<interface_type>& port_);\r | |
128 | \r | |
129 | \r | |
130 | //---------------------------------------------------------\r | |
131 | // Normal binding between port and interface.\r | |
132 | // To be redefined here (bind(port_) is overridden above\r | |
133 | //---------------------------------------------------------\r | |
134 | \r | |
135 | /// bind(interface_type) overridden with port registration \r | |
136 | void bind(interface_type& interface_);\r | |
137 | \r | |
138 | /// operator () (interface_type) overridden with port registration\r | |
139 | void operator () (interface_type& interface_);\r | |
140 | \r | |
141 | /// @}\r | |
142 | \r | |
143 | protected:\r | |
144 | \r | |
145 | /** Returns true and issues an error message and return true if the same interface is bound \r | |
146 | two times throught 2 differents target port. \r | |
147 | **/\r | |
148 | bool is_interface_bound_twice(sc_export_base& target_port_);\r | |
149 | \r | |
150 | };\r | |
151 | \r | |
152 | \r | |
153 | \r | |
154 | //--------------\r | |
155 | // Constructor\r | |
156 | //--------------\r | |
157 | template<typename IF,int N>\r | |
158 | tlm_initiator_port<IF,N>::tlm_initiator_port(const char * name) :\r | |
159 | sc_port<interface_type,N>(name)\r | |
160 | {}\r | |
161 | \r | |
162 | \r | |
163 | /** Returns true and issues an error message if the same interface is bound \r | |
164 | two times throught 2 differents target port. \r | |
165 | **/\r | |
166 | template<typename IF,int N>\r | |
167 | bool tlm_initiator_port<IF,N>::is_interface_bound_twice(sc_export_base& target_port_) {\r | |
168 | for(int i=0;i<this->size();i++) {\r | |
169 | if ((*this)[i] == target_port_.get_interface()) {\r | |
170 | sc_object * tmp = dynamic_cast<sc_object * >(target_port_.get_interface());\r | |
171 | std::string if_name;\r | |
172 | if (tmp) if_name = tmp->name();\r | |
173 | else if_name = "unnamed interface/non sc_object";\r | |
174 | \r | |
175 | std::string msg(sc_object::name());\r | |
176 | msg += (std::string)(": tlm_initiator_port warning, while binding the interface \"");\r | |
177 | msg += if_name + (std::string)("\" exported by target port ");\r | |
178 | msg += (std::string)(target_port_.name()) + (std::string)(": the initiator port is already bound to this interface\n");\r | |
179 | SC_REPORT_WARNING("binding warning",msg.c_str());\r | |
180 | \r | |
181 | return(true);\r | |
182 | }\r | |
183 | }\r | |
184 | return(false);\r | |
185 | }\r | |
186 | \r | |
187 | //---------------------------\r | |
188 | // sc_port overridden methods\r | |
189 | //---------------------------\r | |
190 | \r | |
191 | //-------------------------------------------------------------------------------\r | |
192 | // before_end_of_elaboration()\r | |
193 | // Called just before end of elaboration to propagate registered target ports to all the \r | |
194 | // bound initiator ports\r | |
195 | //-------------------------------------------------------------------------------\r | |
196 | template<typename IF,int N>\r | |
197 | void \r | |
198 | tlm_initiator_port<IF,N>::before_end_of_elaboration()\r | |
199 | {\r | |
200 | \r | |
201 | // Registered target port list propagation (complete sharing of target_port_list between all initiator ports)\r | |
202 | // If current port's target port list exist, share the list with all other port of the chain using the \r | |
203 | // reversed initiator port list.\r | |
204 | if (m_target_port_list.size()) {\r | |
205 | for(typename std::vector<initiator_port_base_type *>::iterator port = get_reversed_initiator_port_list().begin();\r | |
206 | port != get_reversed_initiator_port_list().end();\r | |
207 | port++) { \r | |
208 | \r | |
209 | // Copy the target port(s) to the target port list of the registered initiator (port info. propagation)\r | |
210 | if ((*port) != this) {\r | |
211 | for(typename std::vector<target_port_base_type *>::iterator target_port = m_target_port_list.begin();\r | |
212 | target_port != m_target_port_list.end();\r | |
213 | target_port++) {\r | |
214 | (*port)->register_target_port((*target_port));\r | |
215 | }\r | |
216 | }\r | |
217 | }\r | |
218 | }\r | |
219 | \r | |
220 | // Recreate the complete list of registered initiator_port, from deeper port to higher port (hierarchically speaking)\r | |
221 | // Objective: deeper port is able to "see" all others but intermediate port cannot "see" deeper ports.\r | |
222 | std::vector<initiator_port_base_type *> tmp_initiator_port_list; \r | |
223 | tmp_initiator_port_list.push_back(this);\r | |
224 | this->create_port_list(tmp_initiator_port_list);\r | |
225 | // replace the regular initiator port list: this list is now complete\r | |
226 | this->set_initiator_port_list(tmp_initiator_port_list);\r | |
227 | }\r | |
228 | \r | |
229 | //-------------------------------------------------------------------------------\r | |
230 | // end_of_elaboration()\r | |
231 | // Check the target port list: if empty, stops the simulation as initiator port should be bound at \r | |
232 | // least to one target_port\r | |
233 | //-------------------------------------------------------------------------------\r | |
234 | template<typename IF,int N>\r | |
235 | void \r | |
236 | tlm_initiator_port<IF,N>::end_of_elaboration() {\r | |
237 | \r | |
238 | #ifdef TLM_PORT_DEBUG\r | |
239 | printf("DEBUG\t\t%s: Registered initiator port list :\n",sc_object::name());\r | |
240 | for(typename std::vector<initiator_port_base_type *>::iterator port = get_initiator_port_list().begin();\r | |
241 | port != get_initiator_port_list().end();\r | |
242 | port++) {\r | |
243 | printf("DEBUG\t\t%s: \t- %s\n",sc_object::name(),(static_cast<initiator_port_type * >(*port))->name());\r | |
244 | \r | |
245 | }\r | |
246 | printf("DEBUG\t\t%s: Registered initiator reversed port list :\n",sc_object::name());\r | |
247 | for(typename std::vector<initiator_port_base_type *>::iterator port = get_reversed_initiator_port_list().begin();\r | |
248 | port != get_reversed_initiator_port_list().end();\r | |
249 | port++) {\r | |
250 | printf("DEBUG\t\t%s: \t- %s\n",sc_object::name(),(static_cast<initiator_port_type * >(*port))->name());\r | |
251 | \r | |
252 | }\r | |
253 | \r | |
254 | printf("DEBUG\t\t%s: Registered target port list:\n",sc_object::name());\r | |
255 | for(typename std::vector<target_port_base_type *>::iterator port = get_target_port_list().begin();\r | |
256 | port != get_target_port_list().end();\r | |
257 | port++) {\r | |
258 | printf("DEBUG\t\t%s: \t- %s\n",sc_object::name(),(static_cast<target_port_type * >(*port))->name());\r | |
259 | \r | |
260 | }\r | |
261 | \r | |
262 | printf("DEBUG\t\t%s: -------------------------------------------------------\n",sc_object::name());\r | |
263 | \r | |
264 | #endif\r | |
265 | // Checks the target port list\r | |
266 | if ((!get_target_port_list().size()) && this->size()) {\r | |
267 | std::string msg(sc_object::name());\r | |
268 | msg += (std::string)(": tlm_initiator_port error, target port list is empty. Initiator port should be bound at least to one target port\n");\r | |
269 | SC_REPORT_ERROR("port end of elaboration",msg.c_str());\r | |
270 | }\r | |
271 | }\r | |
272 | \r | |
273 | //--------------------------------------------------------------------\r | |
274 | // Special binding between initiator port and target port.\r | |
275 | // (port registration added to the standard sc_port_base::bind())\r | |
276 | //--------------------------------------------------------------------\r | |
277 | \r | |
278 | //---------------------------------------------------------\r | |
279 | // bind(sc_export)\r | |
280 | //---------------------------------------------------------\r | |
281 | template<typename IF,int N>\r | |
282 | void \r | |
283 | tlm_initiator_port<IF,N>::bind(target_port_type& target_port_) {\r | |
284 | if (!is_interface_bound_twice(target_port_))\r | |
285 | // Registers the target port\r | |
286 | register_target_port(&target_port_);\r | |
287 | \r | |
288 | // Calls sc_port standard bind() method \r | |
289 | sc_port_b<interface_type>::bind(target_port_);\r | |
290 | }\r | |
291 | \r | |
292 | \r | |
293 | template<typename IF,int N>\r | |
294 | template<typename OTHER_IF>\r | |
295 | void \r | |
296 | tlm_initiator_port<IF,N>::bind(tlm_target_port<OTHER_IF>& target_port_) {\r | |
297 | // Test if OTHER_IF derives from IF\r | |
298 | IF * other_if = dynamic_cast<IF*>(target_port_.get_interface());\r | |
299 | if (other_if) {\r | |
300 | \r | |
301 | if (!is_interface_bound_twice(target_port_)) \r | |
302 | // Registers the target port\r | |
303 | this->register_target_port(&target_port_);\r | |
304 | \r | |
305 | // Calls sc_port standard bind() method \r | |
306 | sc_port_b<interface_type>::bind(*other_if);\r | |
307 | }\r | |
308 | else { \r | |
309 | std::string msg(sc_object::name());\r | |
310 | msg += (std::string)(": tlm_initiator_port error, incompatible interface detected during the binding tlm_initiator_port \"") + (std::string)(this->name());\r | |
311 | msg += (std::string)" to tlm_target_port \"" + (std::string)(target_port_.name()) +(std::string)("\"\n") ;\r | |
312 | SC_REPORT_ERROR("bind export to export failed",msg.c_str());\r | |
313 | }\r | |
314 | }\r | |
315 | \r | |
316 | \r | |
317 | \r | |
318 | //---------------------------------------------------------\r | |
319 | // operator() (sc_export): just calls bind(sc_export)\r | |
320 | //---------------------------------------------------------\r | |
321 | template<typename IF,int N>\r | |
322 | void \r | |
323 | tlm_initiator_port<IF,N>::operator() (target_port_type& target_port_) {\r | |
324 | bind(target_port_);\r | |
325 | }\r | |
326 | \r | |
327 | //---------------------------------------------------------\r | |
328 | // bind(sc_port) \r | |
329 | //---------------------------------------------------------\r | |
330 | template<typename IF,int N>\r | |
331 | void \r | |
332 | tlm_initiator_port<IF,N>::bind(sc_port_b<interface_type>& port_) {\r | |
333 | // Register the bound port in the regular list\r | |
334 | this->register_initiator_port(static_cast<initiator_port_type *>(&port_));\r | |
335 | \r | |
336 | // Bound port registers the current port. Used to share the target port list between all port before the end of elaboration\r | |
337 | for(typename std::vector<initiator_port_base_type *>::iterator initiator_port = get_reversed_initiator_port_list().begin();\r | |
338 | initiator_port != get_reversed_initiator_port_list().end();\r | |
339 | initiator_port++) {\r | |
340 | static_cast<initiator_port_type *>(&port_)->reversed_register_initiator_port(*initiator_port);\r | |
341 | }\r | |
342 | \r | |
343 | // Calls sc_port standard bind() method \r | |
344 | sc_port_b<interface_type>::bind(port_);\r | |
345 | }\r | |
346 | \r | |
347 | //---------------------------------------------------------\r | |
348 | // operator() (sc_port): just calls bind(sc_port)\r | |
349 | //---------------------------------------------------------\r | |
350 | template<typename IF,int N>\r | |
351 | void \r | |
352 | tlm_initiator_port<IF,N>::operator() (sc_port_b<interface_type>& port_) {\r | |
353 | bind(port_);\r | |
354 | }\r | |
355 | \r | |
356 | //--------------------------------------------------------------------\r | |
357 | // Normal binding between port and interface\r | |
358 | // To be redefined here (bind(port_) is overridden above\r | |
359 | //--------------------------------------------------------------------\r | |
360 | \r | |
361 | //---------------------------------------------------------\r | |
362 | // bind(interface_type) \r | |
363 | //---------------------------------------------------------\r | |
364 | template<typename IF,int N>\r | |
365 | void \r | |
366 | tlm_initiator_port<IF,N>::bind(interface_type& interface_) {\r | |
367 | // Calls sc_port standard bind method\r | |
368 | sc_port_b<interface_type>::bind(interface_); \r | |
369 | }\r | |
370 | \r | |
371 | //---------------------------------------------------------\r | |
372 | // operator() (interface_type) \r | |
373 | //---------------------------------------------------------\r | |
374 | template<typename IF,int N>\r | |
375 | void \r | |
376 | tlm_initiator_port<IF,N>::operator() (interface_type& interface_) {\r | |
377 | sc_port_b<interface_type>::bind(interface_); \r | |
378 | }\r | |
379 | \r | |
380 | #endif /* _TLM_INITIATOR_PORT_H_ */\r |