| [1] | 1 | /*------------------------------------------------------------\ | 
|---|
 | 2 | |                                                             | | 
|---|
 | 3 | | Tool    :                  systemcass                       | | 
|---|
 | 4 | |                                                             | | 
|---|
 | 5 | | File    :                   sc_port.cc                      | | 
|---|
 | 6 | |                                                             | | 
|---|
 | 7 | | Author  :                 Buchmann Richard                  | | 
|---|
 | 8 | |                           Taktak Sami                       | | 
|---|
 | 9 | |                                                             | | 
|---|
 | 10 | | Date    :                   09_07_2004                      | | 
|---|
 | 11 | |                                                             | | 
|---|
 | 12 | \------------------------------------------------------------*/ | 
|---|
 | 13 |  | 
|---|
 | 14 | /*  | 
|---|
 | 15 |  * This file is part of the Disydent Project | 
|---|
 | 16 |  * Copyright (C) Laboratoire LIP6 - Département ASIM | 
|---|
 | 17 |  * Universite Pierre et Marie Curie | 
|---|
 | 18 |  *  | 
|---|
 | 19 |  * Home page          : http://www-asim.lip6.fr/disydent | 
|---|
 | 20 |  * E-mail             : mailto:richard.buchmann@lip6.fr | 
|---|
 | 21 |  *  | 
|---|
 | 22 |  * This library is free software; you  can redistribute it and/or modify it | 
|---|
 | 23 |  * under the terms  of the GNU Library General Public  License as published | 
|---|
 | 24 |  * by the Free Software Foundation; either version 2 of the License, or (at | 
|---|
 | 25 |  * your option) any later version. | 
|---|
 | 26 |  *  | 
|---|
 | 27 |  * Disydent is distributed  in the hope  that it  will be | 
|---|
 | 28 |  * useful, but WITHOUT  ANY WARRANTY; without even the  implied warranty of | 
|---|
 | 29 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General | 
|---|
 | 30 |  * Public License for more details. | 
|---|
 | 31 |  *  | 
|---|
 | 32 |  * You should have received a copy  of the GNU General Public License along | 
|---|
 | 33 |  * with the GNU C Library; see the  file COPYING. If not, write to the Free | 
|---|
 | 34 |  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 
|---|
 | 35 |  */ | 
|---|
 | 36 |  | 
|---|
 | 37 |  | 
|---|
 | 38 | #include<iomanip> | 
|---|
 | 39 | #include<list> | 
|---|
 | 40 | #include<map> | 
|---|
 | 41 | #include<vector> | 
|---|
 | 42 |  | 
|---|
 | 43 | #include"sc_port.h" | 
|---|
 | 44 | #include"sc_signal.h" | 
|---|
 | 45 | #include"sc_module.h" | 
|---|
 | 46 | #include"entity.h" | 
|---|
 | 47 | #include"global_functions.h" | 
|---|
 | 48 | #include"assert.h" | 
|---|
 | 49 |  | 
|---|
 | 50 | extern "C" { | 
|---|
 | 51 |         extern char unstable; | 
|---|
 | 52 |   char unstable = 0; // not in sc_core namespace because dynamic link support C linkage only | 
|---|
| [4] | 53 |   int32_t pending_write_vector_nb = 0; | 
|---|
| [1] | 54 | } | 
|---|
 | 55 |  | 
|---|
 | 56 | using namespace std; | 
|---|
 | 57 |  | 
|---|
 | 58 | #ifdef CHECK_FSM_RULES | 
|---|
 | 59 | #include"fsm_rules.h" | 
|---|
 | 60 | namespace sc_core { | 
|---|
 | 61 | casc_fsm_step_t casc_fsm_step = ELABORATION; | 
|---|
 | 62 | } | 
|---|
 | 63 | #endif | 
|---|
 | 64 |  | 
|---|
 | 65 | namespace sc_core { | 
|---|
 | 66 |  | 
|---|
 | 67 | const char *const sc_port_base::kind_string = "sc_port"; | 
|---|
 | 68 | const char *const sc_signal_base::kind_string = "sc_signal"; | 
|---|
 | 69 |  | 
|---|
 | 70 | unsigned int pending_write_vector_capacity = 512; | 
|---|
 | 71 | pending_write_vector_t pending_write_vector = NULL; | 
|---|
 | 72 | extern equi_list_t equi_list; | 
|---|
 | 73 |  | 
|---|
 | 74 | const char* get_module_name (const tab_t *pointer) | 
|---|
 | 75 | { | 
|---|
 | 76 |         const equi_t &eq = get_equi (pointer); | 
|---|
 | 77 |   return get_module_name (eq); | 
|---|
 | 78 | } | 
|---|
 | 79 |  | 
|---|
 | 80 | //typedef std::map<const sc_port_base*, const sc_module*> port2module_t; | 
|---|
 | 81 | port2module_t port2module; | 
|---|
 | 82 |  | 
|---|
 | 83 | // KIND STRING | 
|---|
 | 84 | const char * const sc_inout_string = "sc_inout"; | 
|---|
 | 85 | const char * const sc_in_string    = "sc_in"; | 
|---|
 | 86 | const char * const sc_out_string   = "sc_out"; | 
|---|
 | 87 |  | 
|---|
 | 88 | // ---------------------------------------------------------------------------- | 
|---|
 | 89 | //  CLASS : sc_port_base | 
|---|
 | 90 | // | 
|---|
 | 91 | //                                                | 
|---|
 | 92 | // ---------------------------------------------------------------------------- | 
|---|
 | 93 |  | 
|---|
 | 94 | sc_port_base::sc_port_base() | 
|---|
 | 95 | { | 
|---|
 | 96 |         init (); | 
|---|
 | 97 | } | 
|---|
 | 98 |  | 
|---|
 | 99 | sc_port_base::sc_port_base(const char* name_) : sc_object(name_) | 
|---|
 | 100 | { | 
|---|
 | 101 |         init (); | 
|---|
 | 102 | } | 
|---|
 | 103 |  | 
|---|
 | 104 | sc_port_base::sc_port_base(const sc_port_base& parent_) : sc_object (parent_.name ()) | 
|---|
 | 105 | { | 
|---|
 | 106 |         init (); | 
|---|
 | 107 | } | 
|---|
 | 108 |  | 
|---|
 | 109 | void | 
|---|
 | 110 | sc_port_base::init () | 
|---|
 | 111 | { | 
|---|
 | 112 | #ifdef DEBUG | 
|---|
 | 113 |         if (modules_stack.empty ()) { | 
|---|
 | 114 |                 cerr << "Internal error : modules stack empty\n"; | 
|---|
 | 115 |                 exit (9); | 
|---|
 | 116 |         } | 
|---|
 | 117 | #endif | 
|---|
 | 118 |         const sc_module *last_module = sc_core::modules_stack.top (); | 
|---|
 | 119 |         port2module[this] = last_module; | 
|---|
 | 120 |         set_kind (kind_string); | 
|---|
 | 121 | } | 
|---|
 | 122 |  | 
|---|
 | 123 | const sc_module & | 
|---|
 | 124 | sc_port_base::get_module () const | 
|---|
 | 125 | { | 
|---|
 | 126 |         port2module_t::iterator i = port2module.find ((sc_port_base*)this); | 
|---|
 | 127 |         if (i == port2module.end ()) { | 
|---|
 | 128 |                 cerr << "Internal error : Modules contain ports. " | 
|---|
 | 129 |             "SystemCASS needs to identify the module that contains the following port : '"  | 
|---|
 | 130 |         << name() | 
|---|
 | 131 |                           << "'\n"; | 
|---|
 | 132 |                 exit (17); | 
|---|
 | 133 |         } | 
|---|
 | 134 |   const sc_module *m = i->second; | 
|---|
 | 135 |         return *m; | 
|---|
 | 136 | } | 
|---|
 | 137 |  | 
|---|
 | 138 | static bool check_multiwriting2port_error_message = 1; | 
|---|
 | 139 | void | 
|---|
 | 140 | sc_port_base::check_multiwriting2port () const | 
|---|
 | 141 | { | 
|---|
 | 142 |   static std::map<sc_port_base*, double> s; | 
|---|
 | 143 |   double t = sc_simulation_time (); | 
|---|
 | 144 |   if (t == 0) | 
|---|
 | 145 |     return; | 
|---|
 | 146 |   sc_port_base *port = (sc_port_base*)this; | 
|---|
 | 147 |   if ((s[port] == t) && (check_multiwriting2port_error_message)) | 
|---|
 | 148 |   { | 
|---|
 | 149 |     check_multiwriting2port_error_message = 0; | 
|---|
 | 150 |     if (use_port_dependency) | 
|---|
 | 151 |     { | 
|---|
 | 152 |       std::cerr << "Error at cycle #" << t << " : " | 
|---|
 | 153 |                    "SystemCASS allows only 1 writing for each ports/signals.\n" | 
|---|
 | 154 |                 << "Functions write several times into '" << name () << "'.\n"; | 
|---|
 | 155 |     } else { | 
|---|
 | 156 |       std::cerr << "Error : " | 
|---|
 | 157 |                    "Multiwriting to port assertion works only " | 
|---|
 | 158 |                    "when SystemCASS uses port dependency information " | 
|---|
 | 159 |                    "(--p parameter).\n"; | 
|---|
 | 160 |     } | 
|---|
 | 161 |     sc_core::sc_stop (); | 
|---|
 | 162 |     exit (31072006); // 6 | 
|---|
 | 163 |   } else | 
|---|
 | 164 |     s[port] = t; | 
|---|
 | 165 | } | 
|---|
 | 166 |  | 
|---|
 | 167 | std::ostream&  | 
|---|
 | 168 | operator << (std::ostream &o, const sc_port_base &p) | 
|---|
 | 169 | { | 
|---|
 | 170 |   return o << p.name (); | 
|---|
 | 171 | } | 
|---|
 | 172 | // ---------------------------------------------------------------------------- | 
|---|
 | 173 | //  CLASS : sc_signal_base | 
|---|
 | 174 | // | 
|---|
 | 175 | //  The sc_signal<T> primitive channel class. | 
|---|
 | 176 | // ---------------------------------------------------------------------------- | 
|---|
 | 177 |  | 
|---|
 | 178 | void | 
|---|
 | 179 | sc_signal_base::init () | 
|---|
 | 180 | { | 
|---|
 | 181 |         set_kind (kind_string); | 
|---|
 | 182 |         bind (*this); | 
|---|
 | 183 | } | 
|---|
 | 184 |  | 
|---|
 | 185 | sc_signal_base::sc_signal_base() {  | 
|---|
 | 186 |   init (); | 
|---|
 | 187 | } | 
|---|
 | 188 |  | 
|---|
 | 189 | sc_signal_base::sc_signal_base(const char* name_) : sc_object(name_) {  | 
|---|
 | 190 |   init (); | 
|---|
 | 191 | } | 
|---|
 | 192 |  | 
|---|
 | 193 | sc_signal_base::sc_signal_base(const char* name_, void*) : sc_object(name_) { | 
|---|
 | 194 |         // this overload is only used for SC_BIND_PROXY_NIL constant. | 
|---|
 | 195 |         // this signal should not be added to the signal list. | 
|---|
 | 196 | } | 
|---|
 | 197 |  | 
|---|
 | 198 | sc_signal_base::~sc_signal_base() {  | 
|---|
 | 199 | } | 
|---|
 | 200 |  | 
|---|
 | 201 | /* | 
|---|
 | 202 |  * Signals copy | 
|---|
 | 203 |  */ | 
|---|
 | 204 |  | 
|---|
 | 205 | #ifdef DUMP_SIGNAL_STATS | 
|---|
 | 206 | typedef map<tab_t*,long long int> counter_t; | 
|---|
 | 207 | static counter_t  counter; | 
|---|
 | 208 | long long int unnecessary = 0; | 
|---|
 | 209 | long long int total_assig = 0; | 
|---|
 | 210 | #endif | 
|---|
 | 211 |  | 
|---|
 | 212 | } // end of sc_core namespace | 
|---|
 | 213 |  | 
|---|
 | 214 | extern "C" { | 
|---|
 | 215 | void | 
|---|
 | 216 | update () | 
|---|
 | 217 | { | 
|---|
 | 218 | #if defined(DUMP_STAGE) | 
|---|
 | 219 |   cerr << "Updating... "; | 
|---|
 | 220 | #endif | 
|---|
 | 221 | // stl vectors are too slow | 
|---|
 | 222 | // memcopy is not better | 
|---|
 | 223 | // signal table sorting doesn't give any better performance      | 
|---|
 | 224 | #if 0 | 
|---|
 | 225 |         cerr << pending_write_vector_nb << " " << pending_write_vector_capacity << endl; | 
|---|
 | 226 | #endif | 
|---|
 | 227 | #if defined(DUMP_STAGE) | 
|---|
 | 228 |   cerr << "(" << pending_write_vector_nb  | 
|---|
 | 229 |        << " internal pending writings) "; | 
|---|
 | 230 | #endif | 
|---|
 | 231 |         unsigned int i; | 
|---|
 | 232 |         for (i = 0; i < pending_write_vector_nb; ++i) { | 
|---|
 | 233 | #if 0 | 
|---|
 | 234 |                 cerr << "pending_write[" << i << "] : " << pending_write_vector[i]; | 
|---|
 | 235 | #endif | 
|---|
 | 236 | #define iter (sc_core::pending_write_vector[i]) | 
|---|
 | 237 | #ifdef DEBUG | 
|---|
 | 238 |                 if (iter.pointer == NULL) { | 
|---|
 | 239 |                         cerr << "Internal error : trying to apply a posted write from an unassigned signal/port\n"; | 
|---|
 | 240 |                         exit (8); | 
|---|
 | 241 |                 } | 
|---|
 | 242 | #endif   | 
|---|
 | 243 | #ifdef DUMP_SIGNAL_STATS | 
|---|
 | 244 |                 if (*(iter.pointer) == iter.value) | 
|---|
 | 245 |                         unnecessary++; | 
|---|
 | 246 |                 counter[iter.pointer]++; | 
|---|
 | 247 | #endif | 
|---|
 | 248 |                 *(iter.pointer) = iter.value;    | 
|---|
 | 249 | #undef iter | 
|---|
 | 250 |   } | 
|---|
 | 251 | #ifdef DUMP_SIGNAL_STATS | 
|---|
 | 252 |         total_assig += pending_write_vector_nb; | 
|---|
 | 253 | #endif | 
|---|
 | 254 |         pending_write_vector_nb = 0; | 
|---|
 | 255 |  | 
|---|
 | 256 | #if defined(DUMP_STAGE) | 
|---|
 | 257 |   cerr << "done.\n"; | 
|---|
 | 258 | #endif | 
|---|
 | 259 | #if defined(CHECK_MULTIWRITING2REGISTER) | 
|---|
 | 260 |   sc_core::pending_writing2register_clear (); | 
|---|
 | 261 | #endif | 
|---|
 | 262 | } | 
|---|
 | 263 |  | 
|---|
 | 264 | } // end of extern "C" | 
|---|
 | 265 |  | 
|---|
 | 266 | namespace sc_core { | 
|---|
 | 267 |  | 
|---|
 | 268 | void | 
|---|
 | 269 | print_registers_writing_stats (ostream &o) | 
|---|
 | 270 | { | 
|---|
 | 271 | #ifdef DUMP_SIGNAL_STATS | 
|---|
 | 272 |         o << "signal index / name / usage (>1%)\n"; | 
|---|
 | 273 |         o << setprecision (2); | 
|---|
 | 274 |         double t = sc_simulation_time (); | 
|---|
 | 275 |         if (t == 0) { | 
|---|
 | 276 |                 o << "Warning : simulation too short.\n"; | 
|---|
 | 277 |                 t = 0.01; | 
|---|
 | 278 |         } | 
|---|
 | 279 |         if (total_assig == 0) | 
|---|
 | 280 |                 return; | 
|---|
 | 281 |         counter_t::iterator k; | 
|---|
 | 282 |         for (k = counter.begin (); k != counter.end (); ++k) { | 
|---|
 | 283 |                 double usage = k->second / t * 100; | 
|---|
 | 284 |                 if (usage <= 1) | 
|---|
 | 285 |                         continue; | 
|---|
 | 286 |                 o << k->first  | 
|---|
 | 287 |                         << "   " << get_name (k->first)  | 
|---|
 | 288 |                         << "   " << usage << "%\n"; | 
|---|
 | 289 |         } | 
|---|
 | 290 |         typedef map<string,int> counter_module_t; | 
|---|
 | 291 |         counter_module_t counter_by_module; | 
|---|
 | 292 |         for (k = counter.begin (); k != counter.end (); ++k) { | 
|---|
 | 293 |                 string module_name = get_module_name (k->first); | 
|---|
 | 294 |                 counter_by_module[module_name] += k->second;     | 
|---|
 | 295 |         } | 
|---|
 | 296 |         o << "module name / usage\n"; | 
|---|
 | 297 |         counter_module_t::iterator i; | 
|---|
 | 298 |         for (i = counter_by_module.begin (); i != counter_by_module.end (); ++i) { | 
|---|
 | 299 |                 o << i->first  | 
|---|
 | 300 |                         << "   " << (i->second * 100 / total_assig) << "%\n"; | 
|---|
 | 301 |         } | 
|---|
 | 302 |         cerr << "average of assignment number per cycle " << (total_assig / t) << "\n"; | 
|---|
 | 303 |         cerr << (unnecessary * 100 / total_assig) << "% of assignment are unecessary\n"; | 
|---|
 | 304 | #else | 
|---|
 | 305 |         cerr << "Register usage not available.\n"; | 
|---|
 | 306 | #endif | 
|---|
 | 307 | } | 
|---|
 | 308 |  | 
|---|
 | 309 | static | 
|---|
 | 310 | bool | 
|---|
 | 311 | is_bound (/*const*/ sc_port_base &port) | 
|---|
 | 312 | { | 
|---|
 | 313 |   const tab_t *pointer = port.get_pointer (); | 
|---|
 | 314 |   //ASSERT(pointer != NULL); | 
|---|
 | 315 |   if (pointer == NULL) | 
|---|
 | 316 |     return false; // case : sc_in not bound | 
|---|
 | 317 | /* | 
|---|
 | 318 |   equi_t &e = get_equi (pointer); | 
|---|
 | 319 |   if (e.size () == 1) | 
|---|
 | 320 |     return true; // case : sc_out not bound | 
|---|
 | 321 | */ | 
|---|
 | 322 |   return has_equi (port); | 
|---|
 | 323 | } | 
|---|
 | 324 |  | 
|---|
 | 325 | static | 
|---|
 | 326 | void | 
|---|
 | 327 | check_port (/*const*/ sc_port_base &port) | 
|---|
 | 328 | { | 
|---|
 | 329 |   if (!is_bound (port)) | 
|---|
 | 330 |   { | 
|---|
 | 331 |     cerr << "Error : '" << port.name () << "' port" | 
|---|
 | 332 |             " (" << port.kind() << ")" | 
|---|
 | 333 |             " is not bound.\n"; | 
|---|
 | 334 |     exit (29); | 
|---|
 | 335 |   } | 
|---|
 | 336 | } | 
|---|
 | 337 |  | 
|---|
 | 338 | void | 
|---|
 | 339 | check_all_ports () | 
|---|
 | 340 | { | 
|---|
 | 341 |   if (dump_stage) | 
|---|
 | 342 |     cerr << "checking ports..."; | 
|---|
 | 343 |         port2module_t::/*const_*/iterator i; | 
|---|
 | 344 |   for (i = port2module.begin (); i != port2module.end (); ++i) | 
|---|
 | 345 |   { | 
|---|
 | 346 |     /*const*/ sc_port_base *port = i->first; | 
|---|
 | 347 |     ASSERT(port != NULL); | 
|---|
 | 348 |     check_port (*port); | 
|---|
 | 349 |   } | 
|---|
 | 350 |   if (dump_stage) | 
|---|
 | 351 |     cerr << " done."; | 
|---|
 | 352 | } | 
|---|
 | 353 |  | 
|---|
 | 354 | #if defined(CHECK_MULTIWRITING2REGISTER) | 
|---|
 | 355 | typedef set<const tab_t*> pending_writing2register_set_t; | 
|---|
 | 356 | pending_writing2register_set_t pending_writing2register_set; | 
|---|
 | 357 |  | 
|---|
 | 358 | void  | 
|---|
 | 359 | pending_writing2register_clear  () | 
|---|
 | 360 | { | 
|---|
 | 361 |   pending_writing2register_set.clear();  | 
|---|
 | 362 | } | 
|---|
 | 363 |  | 
|---|
 | 364 | void | 
|---|
 | 365 | pending_writing2register_record_and_check (const tab_t *p) | 
|---|
 | 366 | { | 
|---|
 | 367 |   if (pending_writing2register_set.find (p) != pending_writing2register_set.end()) | 
|---|
 | 368 |   { | 
|---|
 | 369 |                 std::cerr << "Error : please check '" << get_name (p) << "'.\n"; | 
|---|
 | 370 |     std::cerr << "Up to 1 writing per register is allowed during a cycle.\n"; | 
|---|
 | 371 |     sc_stop (); | 
|---|
 | 372 |     exit (31072006); // 6 | 
|---|
 | 373 |   } else | 
|---|
 | 374 |     pending_writing2register_set.insert(p); | 
|---|
 | 375 | } | 
|---|
 | 376 | #endif | 
|---|
 | 377 |  | 
|---|
 | 378 | } // end of sc_core namespace | 
|---|
 | 379 |  | 
|---|
 | 380 |  | 
|---|