00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00037 #include "rc_process_support.h"
00038
00039 namespace ReChannel {
00040 namespace internals {
00041
00042 process_support::process_info::reset_signal_map
00043 process_support::process_info::p_reset_signal_map;
00044
00045 const rc_reset_channel_if&
00046
00047 process_support::process_info::_rc_get_reset_channel(
00048 const sc_signal_in_if<bool>& signal_interface)
00049 {
00050 const rc_reset_channel_if* reset_channel =
00051 dynamic_cast<const rc_reset_channel_if*>(&signal_interface);
00052 if (reset_channel == NULL) {
00053 reset_signal*& signal_ = p_reset_signal_map[&signal_interface];
00054 if (signal_ == NULL) {
00055 signal_ = new reset_signal(
00056 sc_gen_unique_name("_rc_process_support_reset_signal"));
00057
00058
00059 sc_spawn_options opt;
00060 {
00061 opt.spawn_method();
00062 opt.set_sensitivity(
00063 &signal_interface.value_changed_event());
00064 }
00065 sc_spawn(
00066 sc_bind(
00067 &process_info::_rc_reset_updater_proc,
00068 sc_cref(signal_interface), sc_ref(*signal_)),
00069 sc_gen_unique_name(
00070 "_rc_process_support_reset_updater_proc"),
00071 &opt);
00072 }
00073 reset_channel = static_cast<const rc_reset_channel_if*>(signal_);
00074 }
00075 return *reset_channel;
00076 }
00077
00078 void process_support::process_info::_rc_reset_updater_proc(
00079 const sc_signal_in_if<bool>& from_, reset_signal& to_)
00080 {
00081 to_.write(from_.read());
00082 }
00083
00084 process_support::process_info::process_info(
00085 boost::function<void (void)> func_,
00086 const rc_process_control& parent_pctrl, bool is_thread_,
00087 bool is_dont_initialize, bool has_sync_reset)
00088 : func(func_), process_control(
00089 parent_pctrl, parent_pctrl.is_active(), has_sync_reset),
00090 p_is_thread(is_thread_), p_is_dont_initialize(false),
00091 p_is_init_run(false)
00092 { }
00093
00094 process_support::process_info::~process_info()
00095 {
00096 for (int level = 0; level <= 1; ++level) {
00097 reset_channel_vector& vector = p_reset_channels[level];
00098 unsigned int count = vector.size();
00099 for (unsigned int i=0; i < count; ++i) {
00100 process_support::unregister_process_control(
00101 *vector[i], process_control);
00102 }
00103 }
00104 }
00105
00106 void process_support::process_info::register_reset_channel(
00107 const rc_reset_channel_if& reset_channel, bool active_level)
00108 {
00109 p_reset_channels[(active_level ? 1 : 0)].push_back(&reset_channel);
00110 process_support::register_process_control(
00111 reset_channel, process_control, active_level);
00112 }
00113
00114 void process_support::process_info::register_reset_interface(
00115 const sc_signal_in_if<bool>& reset_interface, bool active_level)
00116 {
00117 const rc_reset_channel_if& reset_channel =
00118 process_info::_rc_get_reset_channel(reset_interface);
00119 this->register_reset_channel(reset_channel, active_level);
00120 }
00121
00122 void process_support::process_info::register_reset_signal(
00123 const sc_signal<bool>& reset_signal, bool active_level)
00124 {
00125 const rc_reset_channel_if& reset_channel =
00126 process_info::_rc_get_reset_channel(reset_signal);
00127 this->register_reset_channel(reset_channel, active_level);
00128 }
00129
00130 void process_support::process_info::register_reset_port(
00131 const sc_in<bool>& reset_port, bool active_level)
00132 {
00133 const sc_signal_in_if<bool>* const reset_interface =
00134 reset_port.get_interface(0);
00135 if (reset_interface != NULL) {
00136 const rc_reset_channel_if& reset_channel =
00137 process_info::_rc_get_reset_channel(*reset_interface);
00138 this->register_reset_channel(reset_channel, active_level);
00139 } else {
00140 p_reset_ports[(active_level ? 1 : 0)].push_back(&reset_port);
00141 }
00142 }
00143
00144 void process_support::process_info::register_reset_port_interfaces()
00145 {
00146 for (int level = 0; level <= 1; ++level) {
00147 reset_port_vector& reset_ports = p_reset_ports[level];
00148 const unsigned int count = reset_ports.size();
00149 for (unsigned int i=0; i < count; ++i) {
00150 const sc_in<bool>* const reset_port = reset_ports[i];
00151 if (reset_port->get_interface() != NULL) {
00152 this->register_reset_port(*reset_port, level);
00153 }
00154 }
00155 reset_ports.clear();
00156 }
00157 }
00158
00159 void process_support::process_info::update_process_control_state()
00160 {
00161 for (int level = 0; level <= 1; ++level) {
00162 reset_channel_vector& reset_channels = p_reset_channels[level];
00163 const unsigned int count = reset_channels.size();
00164 for (unsigned int i=0; i < count; ++i) {
00165 if (process_support::get_current_level(*reset_channels[i])
00166 == (bool)level) {
00167 if (process_control.is_active()) {
00168 process_control.deactivate();
00169 }
00170 return;
00171 }
00172 }
00173 }
00174 if (!process_control.is_active()) {
00175 process_control.activate();
00176 }
00177 }
00178
00179 process_support::process_support()
00180 : sc_prim_channel(sc_gen_unique_name("_rc_process_support")),
00181 p_reconf(
00182 process_support::_rc_find_context(this->get_parent_object())),
00183 p_last_pinfo(NULL), p_last_host(NULL),
00184 p_last_host_child_count(0)
00185 {
00186
00187 sc_object* parent = this->get_parent_object();
00188 if (dynamic_cast<sc_module*>(parent) == NULL
00189 || dynamic_cast<rc_resettable*>(parent) == NULL)
00190 {
00191 RC_REPORT_ERROR("RC_ID_INVALID_USAGE_",
00192 "Resettable processes are only allowed within"
00193 " resettable modules (in '" << this->name() << "')");
00194 }
00195
00196
00197
00198 rc_non_reconfigurable::get_instance();
00199 }
00200
00201 void process_support::declare_process(
00202 const sc_object& host,
00203 const boost::function<void (void)>& declare_proc_callback,
00204 const boost::function<void (void)>& func, sc_sensitive& sensitive,
00205 bool is_thread, bool dont_initialize, bool has_sync_reset)
00206 {
00207
00208 sc_object* const proc_obj_before =
00209 sc_get_current_process_handle().get_process_object();
00210
00211
00212 const sc_actions actions =
00213 sc_report_handler::set_actions(
00214 SC_WARNING, SC_DO_NOTHING);
00215
00216
00217 declare_proc_callback();
00218
00219
00220 sc_report_handler::set_actions(SC_WARNING, actions);
00221
00222 sc_object* const proc_obj =
00223 sc_get_current_process_handle().get_process_object();
00224
00225
00226 if (proc_obj == NULL || proc_obj == proc_obj_before) {
00227
00228 RC_REPORT_ERROR(RC_ID_INVALID_USAGE_,
00229 "invalid usage (in '" << this->name() << "')");
00230 }
00231
00232 const rc_process_control& reconf_pctrl =
00233 p_reconf.rc_get_process_control();
00234
00235 process_info* const pinfo =
00236 new process_info(
00237 func, reconf_pctrl, is_thread, dont_initialize,
00238 has_sync_reset);
00239 p_reconf_pinfo_map[proc_obj] = pinfo;
00240 p_last_pinfo = pinfo;
00241 p_last_host = &host;
00242 p_last_host_child_count = host.get_child_objects().size();
00243
00244 sensitive << (pinfo->process_control.get_deactivation_event());
00245 }
00246
00247 void process_support::method_process()
00248 {
00249 const sc_process_handle curr_proc = sc_get_current_process_handle();
00250 process_info* const pinfo =
00251 this->_rc_find_process_info(curr_proc.get_process_object());
00252
00253 if (pinfo == NULL || curr_proc.proc_kind() != SC_METHOD_PROC_ )
00254 {
00255 RC_REPORT_ERROR(RC_ID_INVALID_USAGE_,
00256 "invalid usage (in '" << this->name() << "')");
00257 }
00258
00259 const rc_process_control& reconf_pctrl =
00260 p_reconf.rc_get_process_control();
00261
00262 rc_process_registry& preg = rc_get_process_registry();
00263 rc_process_handle hproc = preg.get_process_handle(curr_proc, false);
00264 if (!hproc.valid()) {
00265 hproc = preg.register_process(
00266 curr_proc, pinfo->is_dont_initialize(), true,
00267 pinfo->process_control);
00268 }
00269
00270 if (reconf_pctrl.is_active()) {
00271 if (pinfo->is_init_run() && pinfo->is_dont_initialize()) {
00272 pinfo->set_init_run(false);
00273
00274 return;
00275 }
00276 try {
00277
00278 pinfo->func();
00279
00280 return;
00281 } catch(rc_process_cancel_exception* e) {
00282 delete e;
00283 }
00284 }
00285
00286 if (pinfo->is_dont_initialize()) {
00287 pinfo->set_init_run(true);
00288 }
00289
00290 ::sc_core::next_trigger(reconf_pctrl.get_activation_event());
00291 }
00292
00293 void process_support::thread_process()
00294 {
00295 const sc_process_handle curr_proc = sc_get_current_process_handle();
00296 const std::auto_ptr<process_info> pinfo(
00297 this->_rc_fetch_process_info(curr_proc.get_process_object()));
00298
00299 if (pinfo.get() == NULL || curr_proc.proc_kind() != SC_THREAD_PROC_ )
00300 {
00301 RC_REPORT_ERROR(RC_ID_INVALID_USAGE_,
00302 "invalid usage (in '" << this->name() << "')");
00303 }
00304
00305 rc_process_registry& preg = rc_get_process_registry();
00306 rc_process_handle hproc = preg.get_process_handle(curr_proc, false);
00307 if (!hproc.valid()) {
00308 hproc = preg.register_process(
00309 curr_proc, pinfo->is_dont_initialize(), true,
00310 pinfo->process_control);
00311 }
00312
00313 const rc_process_control& reconf_pctrl =
00314 p_reconf.rc_get_process_control();
00315
00316 pinfo->update_process_control_state();
00317
00318 bool is_dont_initialize_allowed = false;
00319 while(true)
00320 {
00321 bool has_exited_normally = false;
00322
00323 if (reconf_pctrl.is_active()) {
00324 try {
00325 if (is_dont_initialize_allowed
00326 && pinfo->is_dont_initialize())
00327 {
00328
00329 rc_wait();
00330 }
00331
00332 pinfo->func();
00333
00334 has_exited_normally = true;
00335 } catch(rc_process_cancel_exception* e) {
00336 delete e;
00337 }
00338 }
00339
00340
00341 if (!reconf_pctrl.is_active()
00342 || has_exited_normally
00343 || hproc.terminated())
00344 {
00345
00346 if (hproc.is_temporary()) {
00347
00348 hproc.notify_terminated_event();
00349
00350 break;
00351 }
00352
00353
00354 hproc.wait_terminated(reconf_pctrl.get_activation_event());
00355 is_dont_initialize_allowed = true;
00356
00357 } else {
00358 if (pinfo->has_sync_reset()) {
00359 pinfo->update_process_control_state();
00360 if (!pinfo->process_control.is_active()) {
00361 ::sc_core::wait();
00362 pinfo->update_process_control_state();
00363 }
00364 } else {
00365 pinfo->process_control.activate();
00366 }
00367 is_dont_initialize_allowed = false;
00368
00369 }
00370
00371 continue;
00372 }
00373
00374 }
00375
00376 void process_support::dont_initialize(
00377 const sc_object& host) const
00378 {
00379 if (this->has_reconfigurable_context()) {
00380 if (!sc_is_running() && this->_rc_check_valid_last_proc(host)) {
00381 p_last_pinfo->set_dont_initialize(true);
00382 }
00383 }
00384 }
00385
00386 rc_process_handle process_support::rc_spawn(
00387 boost::function<void (void)> func, const char* name_p,
00388 rc_spawn_options* opt_p)
00389 {
00390
00391 if (func.empty()) {
00392 RC_REPORT_ERROR(RC_ID_INVALID_USAGE_,
00393 "invalid usage (in '" << this->name() << "')");
00394 }
00395 sc_spawn_options opt_tmp;
00396 sc_spawn_options* spawn_options;
00397 if (opt_p != NULL) {
00398 spawn_options = static_cast<sc_spawn_options*>(opt_p);
00399 } else {
00400 spawn_options = &opt_tmp;
00401 }
00402
00403 rc_process_registry& preg = rc_get_process_registry();
00404
00405
00406 boost::function<void (void)> entry_func;
00407 if (spawn_options->is_method()) {
00408 entry_func =
00409 boost::bind(&process_support::method_process, this);
00410 } else {
00411 entry_func =
00412 boost::bind(&process_support::thread_process, this);
00413 }
00414
00415 const rc_process_control& reconf_pctrl =
00416 p_reconf.rc_get_process_control();
00417 bool is_thread = !spawn_options->is_method();
00418 bool dont_initialize = (opt_p != NULL && opt_p->is_dont_initialize());
00419 std::auto_ptr<process_info> pinfo(
00420 new process_info(
00421 func, reconf_pctrl, is_thread, dont_initialize, false));
00422
00423 if (opt_p != NULL && !opt_p->is_method()) {
00424 rc_spawn_options::reset_port_vector& rpvec =
00425 opt_p->get_reset_port_vector();
00426 for (rc_spawn_options::reset_port_vector::iterator it =
00427 rpvec.begin(); it != rpvec.end(); ++it)
00428 { pinfo->register_reset_port(*(it->first), it->second); }
00429
00430 rc_spawn_options::reset_signal_vector& rsvec =
00431 opt_p->get_reset_signal_vector();
00432 for (rc_spawn_options::reset_signal_vector::iterator it =
00433 rsvec.begin(); it != rsvec.end(); ++it)
00434 { pinfo->register_reset_signal(*(it->first), it->second); }
00435
00436 rc_spawn_options::reset_channel_vector& rcvec =
00437 opt_p->get_reset_channel_vector();
00438 for (rc_spawn_options::reset_channel_vector::iterator it =
00439 rcvec.begin(); it != rcvec.end(); ++it)
00440 { pinfo->register_reset_channel(*(it->first), it->second); }
00441
00442 rc_spawn_options::process_reset_vector& prvec =
00443 opt_p->get_process_reset_vector();
00444 for (rc_spawn_options::process_reset_vector::iterator it =
00445 prvec.begin(); it != prvec.end(); ++it)
00446 {
00447 pinfo->register_reset_channel(
00448 static_cast<rc_reset_channel_if&>(*(*it)), true);
00449 }
00450 }
00451
00452 const rc_process_control& pctrl = pinfo->process_control;
00453 spawn_options->set_sensitivity(&pctrl.get_deactivation_event());
00454
00455
00456 const sc_actions actions =
00457 sc_report_handler::set_actions(
00458 SC_WARNING, SC_DO_NOTHING);
00459
00460
00461 const sc_process_handle spawned_process =
00462 sc_spawn(entry_func, name_p, spawn_options);
00463
00464
00465 sc_report_handler::set_actions(SC_WARNING, actions);
00466
00467 sc_object* const proc_obj = spawned_process.get_process_object();
00468 p_reconf_pinfo_map[proc_obj] = pinfo.release();
00469
00470 const bool is_temporary = sc_is_running();
00471 return preg.register_process(
00472 spawned_process, dont_initialize, true, pctrl, is_temporary);
00473 }
00474
00475 void process_support::terminate()
00476 {
00477 rc_process_handle hproc = rc_get_current_process_handle();
00478 if (!hproc.terminate()) {
00479 sc_object* parent = this->get_parent_object();
00480 RC_REPORT_ERROR(RC_ID_INVALID_USAGE_,
00481 "attempt to terminate non-reconfigurable process (in '"
00482 << (parent ? parent->name() : "(top level)") << "')");
00483 }
00484 }
00485
00486 bool process_support::reset_signal_is(
00487 const sc_object& host, const sc_in<bool>& reset_port, bool active_level)
00488 {
00489 if (!sc_is_running() && this->_rc_check_valid_last_proc(host)) {
00490
00491 p_last_pinfo->register_reset_port(reset_port, active_level);
00492
00493 p_last_host_child_count = host.get_child_objects().size();
00494 return true;
00495 } else {
00496 return false;
00497 }
00498 }
00499
00500
00501 bool process_support::reset_signal_is(
00502 const sc_object& host, const sc_signal<bool>& reset_signal,
00503 bool active_level)
00504 {
00505 if (!sc_is_running() && this->_rc_check_valid_last_proc(host)) {
00506
00507 p_last_pinfo->register_reset_signal(reset_signal, active_level);
00508
00509 p_last_host_child_count = host.get_child_objects().size();
00510 return true;
00511 } else {
00512 return false;
00513 }
00514 }
00515
00516 const sc_signal<bool>* process_support::reset_channel_is(
00517 const sc_object& host, rc_reset_channel_if& reset_channel,
00518 bool active_level)
00519 {
00520 const sc_signal<bool>* reset_signal = NULL;
00521 if (!sc_is_running() && this->_rc_check_valid_last_proc(host)) {
00522
00523 p_last_pinfo->register_reset_channel(
00524 reset_channel, active_level);
00525 } else {
00526 reset_signal = reset_channel.get_underlying_reset_signal();
00527 if (reset_signal == NULL) {
00528 RC_REPORT_ERROR(RC_ID_INVALID_USAGE_,
00529 "channel cannot be used as a reset signal for"
00530 " standard SC_CTHREAD processes"
00531 " (in '" << host.name() << "')");
00532 }
00533 }
00534 return reset_signal;
00535 }
00536
00537 void process_support::reset_is(
00538 const sc_object& host, rc_process_reset& process_reset)
00539 {
00540 if (!sc_is_running() && this->_rc_check_valid_last_proc(host)) {
00541
00542 p_last_pinfo->register_reset_channel(
00543 static_cast<rc_process_reset&>(process_reset), true);
00544 } else {
00545 RC_REPORT_ERROR(RC_ID_INVALID_USAGE_,
00546 "unrelated reset_is() (in '" << host.name() << "')");
00547 }
00548 }
00549
00550 void process_support::set_sync_reset(const sc_object& host, bool b) const
00551 {
00552 if (!sc_is_running() && this->_rc_check_valid_last_proc(host)) {
00553 if (p_last_pinfo->is_thread()) {
00554 p_last_pinfo->set_sync_reset(b);
00555 } else {
00556 RC_REPORT_WARNING(RC_ID_INVALID_USAGE_,
00557 "rc_set_" << (b ? "sync" : "async") << "_reset()"
00558 " has no effect on method processes (in '"
00559 << host.name() << "')");
00560 }
00561
00562 } else {
00563 RC_REPORT_WARNING(RC_ID_INVALID_USAGE_,
00564 "unrelated rc_set_" << (b ? "sync" : "async") << "_reset()"
00565 " ignored (in '" << host.name() << "')");
00566 }
00567 }
00568
00569 rc_process_behavior_change process_support::disable_process_control() const
00570 {
00571 rc_process_handle hproc = rc_get_current_process_handle();
00572 if (this->has_reconfigurable_context() && hproc.is_cancelable()) {
00573
00574 return hproc.behavior_change(p_reconf.rc_get_process_control());
00575 } else {
00576
00577 return hproc.behavior_change(false);
00578 }
00579 }
00580
00581 void process_support::before_end_of_elaboration()
00582 {
00583 for (process_info_map::iterator it = p_reconf_pinfo_map.begin();
00584 it != p_reconf_pinfo_map.end();
00585 ++it)
00586 {
00587 it->second->register_reset_port_interfaces();
00588 }
00589 }
00590
00591 process_support::process_info* process_support::_rc_find_process_info(
00592 sc_object* proc_obj) const
00593 {
00594 process_info_map::const_iterator it =
00595 p_reconf_pinfo_map.find(proc_obj);
00596 return (it != p_reconf_pinfo_map.end() ? it->second : NULL);
00597 }
00598
00599 process_support::process_info* process_support::_rc_fetch_process_info(
00600 sc_object* proc_obj)
00601 {
00602 process_info_map::iterator it =
00603 p_reconf_pinfo_map.find(proc_obj);
00604 if (it != p_reconf_pinfo_map.end()) {
00605 process_info* const pinfo = it->second;
00606 p_reconf_pinfo_map.erase(it);
00607 return pinfo;
00608 } else {
00609 return NULL;
00610 }
00611 }
00612
00613 bool process_support::_rc_check_valid_last_proc(
00614 const sc_object& host) const
00615 {
00616 return (p_last_pinfo != NULL
00617 && p_last_host == &host
00618 && host.get_child_objects().size() == p_last_host_child_count);
00619 }
00620
00621 rc_reconfigurable& process_support::_rc_find_context(
00622 sc_object* start_search)
00623 {
00624 rc_reconfigurable* const context =
00625 rc_get_reconfigurable_context(start_search);
00626
00627 if (context != NULL) {
00628 return *context;
00629 } else {
00630 return rc_non_reconfigurable::get_instance();
00631 }
00632 }
00633
00634 }
00635
00636 rc_process_reset::rc_process_reset()
00637 : sc_prim_channel(sc_gen_unique_name("_rc_process_reset"))
00638 { }
00639
00640 rc_process_reset::rc_process_reset(const char* name_)
00641 : sc_prim_channel(name_)
00642 { }
00643
00644
00645 void rc_process_reset::trigger()
00646 {
00647 rc_process_handle hproc = rc_get_current_process_handle();
00648 bool was_canceled = hproc.is_canceled();
00649
00650 for (pctrl_set::iterator it = p_pctrl_set.begin();
00651 it != p_pctrl_set.end();
00652 ++it)
00653 {
00654 (*it)->deactivate();
00655 }
00656
00657 if (hproc.is_canceled()) {
00658 if (!was_canceled) {
00659 sc_core::wait(SC_ZERO_TIME);
00660 }
00661 throw new rc_process_cancel_exception();
00662 }
00663 }
00664
00665 void rc_process_reset::register_process_control(
00666 rc_process_control& pctrl, bool active_level) const
00667 {
00668 assert(active_level == true);
00669
00670 if (active_level == true) {
00671 p_pctrl_set.insert(&pctrl);
00672 }
00673 }
00674
00675 void rc_process_reset::unregister_process_control(
00676 rc_process_control& pctrl) const
00677 {
00678 p_pctrl_set.erase(&pctrl);
00679 }
00680
00681 }
00682
00683
00684
00685
00686