From 40ae914829d1517428aac7ee4b8ba68ba5eb96a2 Mon Sep 17 00:00:00 2001 From: brolley Date: Fri, 19 Aug 2005 19:48:45 +0000 Subject: [PATCH] 2005-08-19 Dave Brolley (record_data_memory_write_latency): New virtual method. * Contribute the following changes:n_memory_read_latency. (write_insn_memory): Call record_insn_memory_write_latency. 2005-07-13 Dave Brolley ad_latency. (write_data_memory): Call record_data_memory_write_latency. * mepCfg.cxx (set_dynamic_config): New method of MepMemCfg.::check_level (MepCacheCfg::set_dynamic_config): Don't use the new-config pin or the dynamic-configurator attribute. Instead, relate the cache to the dynamic configurator using its client relation. (MepBoardCfg::write_config): Likewise for the insn_buffer, dmac,result hw_engines and peripherals. Call set_dynamic_config for shared_main_mem. * mainDynamic.cxx (BoardConfig): New struct type. (main): Keep a vector of the boards in board_configs. Call:ok. set_start_config for each board after all the --wrap options have been seen. Call add_wrapped_component to identify each wrapped component to the session.y@redhat.com> * commonCfg.h (wrapped_components): New member of SessionCfg. (add_wrapped_component): New method of SessionCfg.New class. (wrap_config): Likewise.ule): Reschedule after the given number of * commonCfg.cxx (wrap_config): New method of SessionCfg. (profile_config): Use possible_wrap_name to obtain the component being wrapped so we can get its name. (GdbCfg::write_config): Don't connect the new-config pin or use the dynamic-configurator relation. Instead, use the dynamic configurator's client relation. (BoardCfg::write_config): Likewise. Relate the dynamic configurator to gloss. * baseCfg.cxx (wrap_component): Now returns AtomicCfg *. (possible_wrap_name): Likewise. (dynamic_config_for_wrapped_children): Don't connect the dynamic configurator's new-config pin to the components or relate the dynamic configurator to them. Rather, relate the components to the dynamic configurator using its 'client' relation. * baseCfg.h (wrap_component): Now returns AtomicCfg *. (possible_wrap_name): Likewise. 2005-07-05 Dave Brolley * commonCfg.cxx (BoardCfg::write_load): Connect dynamic configurator's "reset" pin to output 2 of reset_net. (write_config): Set the "start-config" attribute of the dynamic configurator not gloss. Relate "main" to the dynamic configurator unconditionally. Connect the "config-error" pins of the dynamic configurator and gloss. 2005-06-30 Dave Brolley * mainDynamic.cxx (try_add_gprof): Make sure an argument is specified after the comma. 2005-06-06 Dave Brolley * mainDynamic.cxx (need_sess): Now takes 'verbose' argument. Use it to initialize sess->verbose. Update all callers. (main): Add " --model-busses" to board_start_config instead of " --model_busses" (typo). * commonCfg.h (need_core_probe): New member of SessionCfg. (BoardCfg::dynamic_configurator): Now public. * commonCfg.cxx (SessionCfg): Initialize need_core_probe. (profile_config): Set need_core_probe for --trace-core. Call use_tcl_bridge and possible_wrap_name for --wrap. (LoaderCfg): Don't set verbose? attribute here. (GlossCfg): Likewise. (GdbCfg::write_config): Connect the stub and the socket to the dynamic_configurator. (BoardCfg): Initialize core_probe and warmup_funcs. Connect the cpu's print-insn-summary pin to the shutdown sequence here. (BoardCfg::write_load): Connect the dynamic configurator's step! pin to the init-sequence's output 6. Set the core_probe's trace? attribute. Set the gloss and loader's verbose? attributes. (BoardCfg::write_config): Give the dynamic configurator its own subscription to sim-sched. Set the cpu's 'main' and core-probe relations. Connect gloss, core_probe, loader and all of the board's wrapped childred to the dynamic configurator. Check whether components are wrapped before connecting them to the dynamic configurator. Don't co nnect the cpu's print-insn-summary pin to the shutdown sequence here. * baseCfg.cxx (AtomicCfg): Initialize my_possibly_wrapped. (wrap_component): Set my_possibly_wrapped. (possible_wrap_name): New static method of AtomicCfg. (AtomicCfg::write_construct): Check my_possibly_wrapped. Set victim-trace? to false if only possibly wrapped. (dynamic_config_for_wrapped_children): New method of AggregateCfg. * baseCfg.h (possible_wrap_name): New static method of AtomicCfg. (possibly_wrapped): New method of AtomicCfg. (my_possibly_wrapped): New member of AtomicCfg. (dynamic_config_for_wrapped_children): New method of AggregateCfg. 2005-05-29 Dave Brolley * mainDynamic.cxx (usage): Document --profile-config,--profile-func, --warmup-func and --warmup. (Defs): Initialize warmup, profile_func and start_config. (warmup,profile_func,warmup_func,start_config): New members of Defs. (need_sess): Call profile_config with "sid-internal-warmup:". (opt_warmup,opt_warmup_func,opt_profile_func,opt_profile_config): New enumerators. (long_options): Add --profile-config,--profile-func, --warmup-func and --warmup. (main): Accumulate start_config with reconfigurable options which occur before the first --board. For each board call set_start_config with the value of start_config concatenated with the additional reconfigurabl e options specified for that --board. Call set_warmup, add_warmup_func and add_profile_func for each board. Handle new option enums. * commonCfg.h (add_profile_config): New method of SessionCfg. (profile_config_error, profile_opt_value, profile_opt_int_value) (profile_opt_gprof_value, match_profile_opt, profile_config): New methods of SessionCfg. (GprofCfg): New constructor. (write_load): New virtual override in BoardCfg. (add_profile_func, add_warmup_func, set_warmup, set_start_config): New methods of BoardCfg. (need_gprof): New member of BoardCfg. (start_config,warmup_funcs,profile_funcs): New members of BoardCfg. * commonCfg.cxx (SessionCfg): Initialize need_gprof. (add_profile_config): New method of SessionCfg. (profile_config_error, profile_opt_value, profile_opt_int_value) (profile_opt_gprof_value, match_profile_opt, profile_config): New methods of SessionCfg. (GprofCfg): Always add a sunscription to sim_sched. Set the sim-sched-event attribute. (GprofCfg): New constructor. (BoardCfg): Initialize dynamic_configurator and start_config. (write_load): New virtual override in BoardCfg. (BoardCfg::write_config): Make connections and set attributes to allow for dynamic configuration. (add_profile_func, add_warmup_func, set_warmup, set_start_config): New methods of BoardCfg. --- sid/main/dynamic/ChangeLog | 129 ++++++++++++++ sid/main/dynamic/baseCfg.cxx | 57 +++++- sid/main/dynamic/baseCfg.h | 9 +- sid/main/dynamic/commonCfg.cxx | 370 ++++++++++++++++++++++++++++++++++++++- sid/main/dynamic/commonCfg.h | 28 +++ sid/main/dynamic/mainDynamic.cxx | 221 +++++++++++++++++++---- 6 files changed, 763 insertions(+), 51 deletions(-) diff --git a/sid/main/dynamic/ChangeLog b/sid/main/dynamic/ChangeLog index 177aebb5eb..04b5c7e0b3 100644 --- a/sid/main/dynamic/ChangeLog +++ b/sid/main/dynamic/ChangeLog @@ -1,3 +1,132 @@ +2005-08-19 Dave Brolley + + * Contribute the following changes: + + 2005-07-13 Dave Brolley + + * mepCfg.cxx (set_dynamic_config): New method of MepMemCfg. + (MepCacheCfg::set_dynamic_config): Don't use the new-config pin + or the dynamic-configurator attribute. Instead, relate the cache + to the dynamic configurator using its client relation. + (MepBoardCfg::write_config): Likewise for the insn_buffer, dmac, + hw_engines and peripherals. Call set_dynamic_config for shared_main_mem. + * mainDynamic.cxx (BoardConfig): New struct type. + (main): Keep a vector of the boards in board_configs. Call + set_start_config for each board after all the --wrap options have + been seen. Call add_wrapped_component to identify each wrapped + component to the session. + * commonCfg.h (wrapped_components): New member of SessionCfg. + (add_wrapped_component): New method of SessionCfg. + (wrap_config): Likewise. + * commonCfg.cxx (wrap_config): New method of SessionCfg. + (profile_config): Use possible_wrap_name to obtain the component + being wrapped so we can get its name. + (GdbCfg::write_config): Don't connect the new-config pin or use the + dynamic-configurator relation. Instead, use the dynamic configurator's + client relation. + (BoardCfg::write_config): Likewise. Relate the dynamic configurator + to gloss. + * baseCfg.cxx (wrap_component): Now returns AtomicCfg *. + (possible_wrap_name): Likewise. + (dynamic_config_for_wrapped_children): Don't connect the dynamic + configurator's new-config pin to the components or relate the + dynamic configurator to them. Rather, relate the components to the + dynamic configurator using its 'client' relation. + * baseCfg.h (wrap_component): Now returns AtomicCfg *. + (possible_wrap_name): Likewise. + + 2005-07-05 Dave Brolley + + * commonCfg.cxx (BoardCfg::write_load): Connect dynamic configurator's + "reset" pin to output 2 of reset_net. + (write_config): Set the "start-config" attribute of the dynamic + configurator not gloss. Relate "main" to the dynamic configurator + unconditionally. Connect the "config-error" pins of the dynamic + configurator and gloss. + + 2005-06-30 Dave Brolley + + * mainDynamic.cxx (try_add_gprof): Make sure an argument is specified + after the comma. + + 2005-06-06 Dave Brolley + + * mainDynamic.cxx (need_sess): Now takes 'verbose' argument. Use it + to initialize sess->verbose. Update all callers. + (main): Add " --model-busses" to board_start_config instead of + " --model_busses" (typo). + * commonCfg.h (need_core_probe): New member of SessionCfg. + (BoardCfg::dynamic_configurator): Now public. + * commonCfg.cxx (SessionCfg): Initialize need_core_probe. + (profile_config): Set need_core_probe for --trace-core. Call + use_tcl_bridge and possible_wrap_name for --wrap. + (LoaderCfg): Don't set verbose? attribute here. + (GlossCfg): Likewise. + (GdbCfg::write_config): Connect the stub and the socket to the + dynamic_configurator. + (BoardCfg): Initialize core_probe and warmup_funcs. Connect the cpu's + print-insn-summary pin to the shutdown sequence here. + (BoardCfg::write_load): Connect the dynamic configurator's step! pin + to the init-sequence's output 6. Set the core_probe's trace? + attribute. Set the gloss and loader's verbose? attributes. + (BoardCfg::write_config): Give the dynamic configurator its own + subscription to sim-sched. Set the cpu's 'main' and core-probe + relations. Connect gloss, core_probe, loader and all of the board's + wrapped childred to the dynamic configurator. Check whether components + are wrapped before connecting them to the dynamic configurator. Don't connect + the cpu's print-insn-summary pin to the shutdown sequence here. + * baseCfg.cxx (AtomicCfg): Initialize my_possibly_wrapped. + (wrap_component): Set my_possibly_wrapped. + (possible_wrap_name): New static method of AtomicCfg. + (AtomicCfg::write_construct): Check my_possibly_wrapped. Set + victim-trace? to false if only possibly wrapped. + (dynamic_config_for_wrapped_children): New method of AggregateCfg. + * baseCfg.h (possible_wrap_name): New static method of AtomicCfg. + (possibly_wrapped): New method of AtomicCfg. + (my_possibly_wrapped): New member of AtomicCfg. + (dynamic_config_for_wrapped_children): New method of AggregateCfg. + + 2005-05-29 Dave Brolley + + * mainDynamic.cxx (usage): Document --profile-config,--profile-func, + --warmup-func and --warmup. + (Defs): Initialize warmup, profile_func and start_config. + (warmup,profile_func,warmup_func,start_config): New members of Defs. + (need_sess): Call profile_config with "sid-internal-warmup:". + (opt_warmup,opt_warmup_func,opt_profile_func,opt_profile_config): New + enumerators. + (long_options): Add --profile-config,--profile-func, + --warmup-func and --warmup. + (main): Accumulate start_config with reconfigurable options which occur + before the first --board. For each board call set_start_config with + the value of start_config concatenated with the additional reconfigurable + options specified for that --board. Call set_warmup, add_warmup_func and + add_profile_func for each board. Handle new option enums. + * commonCfg.h (add_profile_config): New method of SessionCfg. + (profile_config_error, profile_opt_value, profile_opt_int_value) + (profile_opt_gprof_value, match_profile_opt, profile_config): New + methods of SessionCfg. + (GprofCfg): New constructor. + (write_load): New virtual override in BoardCfg. + (add_profile_func, add_warmup_func, set_warmup, set_start_config): New + methods of BoardCfg. + (need_gprof): New member of BoardCfg. + (start_config,warmup_funcs,profile_funcs): New members of BoardCfg. + * commonCfg.cxx (SessionCfg): Initialize need_gprof. + (add_profile_config): New method of SessionCfg. + (profile_config_error, profile_opt_value, profile_opt_int_value) + (profile_opt_gprof_value, match_profile_opt, profile_config): New + methods of SessionCfg. + (GprofCfg): Always add a sunscription to sim_sched. Set the + sim-sched-event attribute. + (GprofCfg): New constructor. + (BoardCfg): Initialize dynamic_configurator and start_config. + (write_load): New virtual override in BoardCfg. + (BoardCfg::write_config): Make connections and set attributes to allow + for dynamic configuration. + (add_profile_func, add_warmup_func, set_warmup, set_start_config): New + methods of BoardCfg. + 2005-06-03 Jim Blandy * Makefile.am (LIBIBERTY): Link against the libiberty.a from diff --git a/sid/main/dynamic/baseCfg.cxx b/sid/main/dynamic/baseCfg.cxx index 41519082b8..65695f6a02 100644 --- a/sid/main/dynamic/baseCfg.cxx +++ b/sid/main/dynamic/baseCfg.cxx @@ -229,7 +229,8 @@ map AtomicCfg_impl::atomic_names; AtomicCfg::AtomicCfg (const string name, const string complib, const string compsym, const string comptype) : ComponentCfg (name), - wrapped (false), + my_wrapped (false), + my_possibly_wrapped (false), my_complib (complib), my_compsym (compsym), my_comptype (comptype) @@ -245,13 +246,27 @@ void AtomicCfg::add_prefix (const string prefix) AtomicCfg::~AtomicCfg() {} -bool AtomicCfg::wrap_component (const string name) +AtomicCfg *AtomicCfg::wrap_component (const string name) { if (AtomicCfg_impl::atomic_names.find (name) == AtomicCfg_impl::atomic_names.end ()) - return false; - AtomicCfg_impl::atomic_names[name]->wrapped = true; - return true; + return 0; + AtomicCfg *comp = AtomicCfg_impl::atomic_names[name]; + comp->my_wrapped = true; + comp->my_possibly_wrapped = false; + return comp; +} + +AtomicCfg * +AtomicCfg::possible_wrap_name (const string &name) +{ + if (AtomicCfg_impl::atomic_names.find (name) == + AtomicCfg_impl::atomic_names.end ()) + return 0; + AtomicCfg *comp = AtomicCfg_impl::atomic_names[name]; + if (! comp->my_wrapped) + comp->my_possibly_wrapped = true; + return comp; } void AtomicCfg::reset_load_map () @@ -276,11 +291,14 @@ void AtomicCfg::write_construct (Writer &w) { if (my_comptype == "") return; - if (wrapped) + if (my_wrapped || my_possibly_wrapped) { w.write_line ("new sid-api-trace " + my_name); w.write_line ("new " + my_comptype + " " + my_name + "-traced"); w.write_line ("relate " + my_name + " victim " + my_name + "-traced"); + w.write_line ("set " + my_name + " victim-name " + my_name + "-traced"); + if (my_possibly_wrapped) + w.write_line ("set " + my_name + " victim-trace? 0"); } else w.write_line ("new " + my_comptype + " " + my_name); @@ -375,6 +393,33 @@ const ResolvedName AggregateCfg::resolve(const role r, const string name) } +void AggregateCfg::dynamic_config_for_wrapped_children (AtomicCfg *dynamic_configurator, Writer &w) +{ + assert (dynamic_configurator); + for (vector::const_iterator i = a_impl->my_children.begin(); + i != a_impl->my_children.end(); ++i) + { + if (*i == dynamic_configurator) + continue; + AtomicCfg *a = dynamic_cast(*i); + if (a) + { + if (a->possibly_wrapped ()) + { + Relation (dynamic_configurator, "client", a).write_to (w); + } + continue; + } + AggregateCfg *ag = dynamic_cast(*i); + if (ag) + { + ag->dynamic_config_for_wrapped_children (dynamic_configurator, w); + continue; + } + assert (false); + } +} + Connection::Connection (ComponentCfg *src, const string srcport, ComponentCfg *dst, const string dstport, diff --git a/sid/main/dynamic/baseCfg.h b/sid/main/dynamic/baseCfg.h index 57b4d4ecb1..58910cc080 100644 --- a/sid/main/dynamic/baseCfg.h +++ b/sid/main/dynamic/baseCfg.h @@ -99,10 +99,14 @@ virtual public ComponentCfg virtual void write_load (Writer &w); virtual void write_construct (Writer &w); static void reset_load_map (); - static bool wrap_component (const string name); + static AtomicCfg *wrap_component (const string name); + static AtomicCfg *possible_wrap_name (const string &comp_name); string comp_type () const { return my_comptype; } + bool wrapped () const { return my_wrapped; } + bool possibly_wrapped () const { return my_wrapped || my_possibly_wrapped; } protected: - bool wrapped; + bool my_wrapped; + bool my_possibly_wrapped; string my_complib; string my_compsym; string my_comptype; @@ -120,6 +124,7 @@ virtual public ComponentCfg virtual void write_config (Writer &w); void add_child (ComponentCfg *c); virtual const ResolvedName resolve(const role r, const string name); + void dynamic_config_for_wrapped_children (AtomicCfg *dynamic_configurator, Writer &w); protected: AggregateCfg_impl *a_impl; }; diff --git a/sid/main/dynamic/commonCfg.cxx b/sid/main/dynamic/commonCfg.cxx index 4089805fec..44c81a7b9a 100644 --- a/sid/main/dynamic/commonCfg.cxx +++ b/sid/main/dynamic/commonCfg.cxx @@ -573,6 +573,8 @@ SessionCfg::SessionCfg (const string name) loader (NULL), verbose (false), use_stdio (true), + need_gprof (false), + need_core_probe (false), board_count (0), gdb_count (0) { @@ -615,6 +617,12 @@ SessionCfg::add_ulog_file (const string name) add_child (ulog); } +void +SessionCfg::add_profile_config (const string &name, const string &options) +{ + set (main_obj, "dynamic-config!", name + "|" + options); +} + void SessionCfg::set_loader (LoaderCfg *l) { if (loader) @@ -701,6 +709,178 @@ void SessionCfg::use_tcl_bridge () init_seq->add_output (7, tcl_bridge, "!event"); } +string +SessionCfg::wrap_config () +{ + string spec; + for (vector::const_iterator it = wrapped_components.begin (); + it != wrapped_components.end (); + ++it) + spec += " --wrap=" + (*it)->get_name (); + return spec; +} + +// Process the argument to --profile-config which will +// be a subset of the allowable SID command line options +// which can be dynamically changed. +// +void +SessionCfg::profile_config_error (const string &spec) +{ + cerr << "error: invalid argument to --profile-config: " << spec << endl; + exit (8); +} + +string +SessionCfg::profile_opt_value (const string& opt, const vector& opt_parts, unsigned max_parts) +{ + unsigned size = opt_parts.size (); + if (size > max_parts) + profile_config_error (opt); // doesn't return + + if (max_parts == 1) + return "true"; + + return opt_parts[1]; +} + +string +SessionCfg::profile_opt_int_value (const string& opt, const vector& opt_parts) +{ + unsigned size = opt_parts.size (); + if (size != 2) + profile_config_error (opt); // doesn't return + + unsigned n; + sid::component::status s = sidutil::parse_attribute (opt_parts[1], n); + if (s != sid::component::ok) + profile_config_error (opt); // doesn't return + + return opt_parts[1]; +} + +string +SessionCfg::profile_opt_gprof_value (const string& opt, const vector& opt_parts) +{ + unsigned size = opt_parts.size (); + if (size < 2 || size > 3) + profile_config_error (opt); // doesn't return + + vector sub_parts = sidutil::tokenize (opt_parts[1], ","); + string value = sub_parts[0]; + if (size == 3) + { + if (sub_parts.size () != 2 || sub_parts[1] != "cycles") + profile_config_error (opt); // doesn't return + + unsigned n; + sid::component::status s = sidutil::parse_attribute (opt_parts[2], n); + if (s != sid::component::ok) + profile_config_error (opt); // doesn't return + + value += "," + opt_parts[2]; + } + + need_gprof = true; + return value; +} + +bool +SessionCfg::match_profile_opt (const string &opt, const string& want, unsigned min_size) +{ + unsigned opt_size = opt.size (); + unsigned want_size = want.size (); + if (opt_size < min_size || opt_size > want_size) + return false; + return opt == want.substr (0, opt_size); +} + +void +SessionCfg::profile_config (const string &spec) +{ + // Extract the name of the config profile + vector parts = sidutil::tokenize (spec, ":"); + if (parts.size () != 2) + profile_config_error (spec); + string name = parts[0]; + + // Initialize the candidate options to their default values. + string trace_extract = "false"; + string trace_semantics = "false"; + string trace_disassemble = "false"; + string trace_core = "false"; + string trace_counter = "false"; + string ulog_level = "0"; + string ulog_mode = "less"; + string wrap = ""; + string verbose = "false"; + string final_insn_count = "false"; + string gprof = ""; + string insn_count = "10000"; + + // Now examine the spec and reset those which are specified. + vectoropts = sidutil::tokenize (parts[1], " "); + int size = opts.size (); + for (int i = 0; i < size; ++i) + { + const string opt = opts[i]; + vector opt_parts = sidutil::tokenize (opt, "="); + const string opt_name = opt_parts[0]; + + if (match_profile_opt (opt_name, "--trace-extract", 9)) + trace_extract = profile_opt_value (opt, opt_parts, 1); + else if (match_profile_opt (opt_name, "--trace-semantics", 9)) + trace_semantics = profile_opt_value (opt, opt_parts, 1); + else if (match_profile_opt (opt_name, "--trace-disassemble", 9)) + trace_disassemble = profile_opt_value (opt, opt_parts, 1); + else if (match_profile_opt (opt_name, "--trace-core", 11)) + { + trace_core = profile_opt_value (opt, opt_parts, 1); + need_core_probe = true; + } + else if (match_profile_opt (opt_name, "--trace-counter", 11)) + trace_counter = profile_opt_value (opt, opt_parts, 1); + else if (match_profile_opt (opt_name, "--ulog-level=", 8)) + ulog_level = profile_opt_int_value (opt, opt_parts); + else if (match_profile_opt (opt_name, "--ulog-mode=", 8)) + ulog_mode = profile_opt_value (opt, opt_parts, 2); + else if (match_profile_opt (opt_name, "--verbose", 3)) + verbose = profile_opt_value (opt, opt_parts, 1); + else if (match_profile_opt (opt_name, "--wrap=", 3)) + { + string comp_name = profile_opt_value (opt, opt_parts, 2); + use_tcl_bridge (); + AtomicCfg *comp = AtomicCfg::possible_wrap_name (comp_name); + if (! wrap.empty ()) wrap += ","; + if (comp) + wrap += comp->get_name (); + else + wrap += comp_name; + } + else if (match_profile_opt (opt_name, "--final-insn-count", 3)) + final_insn_count = profile_opt_value (opt, opt_parts, 1); + else if (match_profile_opt (opt_name, "--gprof=", 3)) + gprof = profile_opt_gprof_value (opt, opt_parts); + else if (match_profile_opt (opt_name, "--insn-count=", 3)) + insn_count = profile_opt_int_value (opt, opt_parts); + } + + // Now contruct a string representing the complete configuration + add_profile_config (name, + "trace-extract=" + trace_extract + ":" + + "trace-semantics=" + trace_semantics + ":" + + "trace-disassemble=" + trace_disassemble + ":" + + "trace-core=" + trace_core + ":" + + "trace-counter=" + trace_counter + ":" + + "ulog-level=" + ulog_level + ":" + + "ulog-mode=" + ulog_mode + ":" + + "wrap=" + wrap + ":" + + "verbose=" + verbose + ":" + + "final-insn-count=" + final_insn_count + ":" + + "gprof=" + gprof + ":" + + "insn-count=" + insn_count); +} + void SessionCfg::write_config (Writer &w) { AggregateCfg::write_config (w); @@ -733,7 +913,6 @@ LoaderCfg::LoaderCfg (const string name, { assert (sess); set (this, "file", "a.out"); - set (this, "verbose?", sess->verbose ? "true" : "false"); conn_pin (this, "error", sess->main_obj, "stop!"); sess->init_seq->add_output (1, this, "load!"); } @@ -778,7 +957,6 @@ GlossCfg::GlossCfg (const string name, conn_pin (this, "trap", cpu, "trap", both); conn_pin (this, "trap-code", cpu, "trap-code", dst_to_src); conn_bus (this, "target-memory", mem, mem_bus_name); - set (this, "verbose?", sess->verbose ? "true" : "false"); assert (sess->init_seq); sess->init_seq->add_output (2, this, "reset"); } @@ -796,12 +974,10 @@ GlossCfg::GlossCfg (const string name, relate (this, "cpu", cpu); conn_pin (this, "trap", cpu, "trap", both); conn_pin (this, "trap-code", cpu, "trap-code", dst_to_src); - set (this, "verbose?", sess->verbose ? "true" : "false"); assert (sess->init_seq); sess->init_seq->add_output (2, this, "reset"); } - // GprofCfg GprofCfg::~GprofCfg() {} GprofCfg::GprofCfg (const string name, @@ -817,10 +993,13 @@ GprofCfg::GprofCfg (const string name, { assert (cpu); assert (sess); + // Add a subscription to the target scheduler. Even if it's not + // used now, it could be used due to dynamic configuration. + assert (sess->sim_sched); + int slot = sess->sim_sched->add_subscription (this, "sample"); + if (type == simulated_cycles) { - assert (sess->sim_sched); - int slot = sess->sim_sched->add_subscription (this, "sample"); sess->sim_sched->set_regular (slot, true); sess->sim_sched->set_time (slot, interval); } @@ -837,6 +1016,30 @@ GprofCfg::GprofCfg (const string name, set (this, "value-attribute", "pc"); set (this, "bucket-size", "4"); // bytes-per-bucket set (this, "output-file", filename); + set (this, "sim-sched-event", sidutil::make_attribute (slot)); +} + +// Create a gprof component but don't activate it +GprofCfg::GprofCfg (const string name, + CpuCfg *cpu, + SessionCfg *sess) : + ComponentCfg (name), + AtomicCfg ( name, "libprof.la", + "prof_component_library", + "sw-profile-gprof") +{ + assert (cpu); + assert (sess); + // Add a subscription to the target scheduler. Even if it's not + // used now, it could be used due to dynamic configuration. + assert (sess->sim_sched); + int slot = sess->sim_sched->add_subscription (this, "sample"); + + sess->shutdown_seq->add_output (7, this, "store"); + relate (this, "target-component", cpu); + set (this, "value-attribute", "pc"); + set (this, "bucket-size", "4"); // bytes-per-bucket + set (this, "sim-sched-event", sidutil::make_attribute (slot)); } @@ -914,6 +1117,19 @@ void GdbCfg::write_config (Writer &w) Setting (stub, "trace-gdbserv?", "true").write_to (w); Setting (sock, "verbose?", "true").write_to (w); } + + // the stub and socket need to be connected to the dynamic_configurator. + if (board->dynamic_configurator) + { + if (! stub->possibly_wrapped ()) + { + Relation (board->dynamic_configurator, "client", stub).write_to (w); + } + if (! sock->possibly_wrapped ()) + { + Relation (board->dynamic_configurator, "client", sock).write_to (w); + } + } } @@ -938,7 +1154,11 @@ BoardCfg::BoardCfg (const string name, main_mapper (NULL), icache (NULL), dcache (NULL), - loader (NULL) + loader (NULL), + core_probe (0), + dynamic_configurator (NULL), + start_config (""), + warmup_funcs ("_Sid_config") { assert (sess); cpu = new CpuCfg ("cpu", default_cpu_variant, sess); @@ -958,6 +1178,9 @@ BoardCfg::BoardCfg (const string name, cpu->set_imem (main_mapper, "access-port"); cpu->set_dmem (main_mapper, "access-port"); } + + sess->shutdown_seq->add_output (0, cpu, "print-insn-summary!"); + add_child (cpu); add_child (main_mapper); add_child (cache_flush_net); @@ -997,9 +1220,49 @@ void BoardCfg::set_loader (LoaderCfg *l) add_child (l); } +void BoardCfg::write_load (Writer &w) +{ + if (gloss) + { + // Create a dynamic reconfigurator to be used by this gloss + dynamic_configurator = new AtomicCfg ("dynamic-config", "libconfig.la", + "config_component_library", + "sid-control-dynamic-configurator"); + sess->init_seq->add_output (6, dynamic_configurator, "step!"); + sess->reset_net->add_output (2, dynamic_configurator, "reset"); + sess->sim_sched->add_subscription (dynamic_configurator, "step!", "step-control"); + add_child (dynamic_configurator); + + // If we may need a gprof for dynamic configuration but don't have + // one yet, then create a disabled one. + if (! gprof && sess->need_gprof) + { + gprof = new GprofCfg ("gprof", cpu, sess); + add_child (gprof); + } + + // If we may need a core_probe for dynamic configuration but don't have + // one yet, then create a disabled one. + if (! core_probe && sess->need_core_probe) + { + trace_core (); + core_probe->set (core_probe, "trace?", "false"); + } + + if (sess->verbose) + set (gloss, "verbose?", "true"); + } + if (loader) + if (sess->verbose) + set (loader, "verbose?", "true"); + + AggregateCfg::write_load (w); +} + void BoardCfg::write_config (Writer &w) { AggregateCfg::write_config (w); + if (gloss) { if (gdb) @@ -1024,6 +1287,68 @@ void BoardCfg::write_config (Writer &w) PinConnection (gloss, "process-signal", sess->main_obj, "stop!").write_to(w); PinConnection (gloss, "process-signal", sess->yield_net, "input").write_to(w); } + + // Set up for dynamic configuration + assert (dynamic_configurator); + Relation (dynamic_configurator, "main", sess->main_obj).write_to (w); + PinConnection (dynamic_configurator, "step-control", cpu, "yield").write_to (w); + Relation (gloss, "main", sess->main_obj).write_to (w); + Relation (gloss, "dynamic-configurator", dynamic_configurator).write_to (w); + PinConnection (gloss, "configure", dynamic_configurator, "configure!").write_to (w); + PinConnection (dynamic_configurator, "config-result", gloss, "config-result").write_to (w); + PinConnection (dynamic_configurator, "config-error", gloss, "config-error").write_to (w); + + // Set the starting configuration + if (start_config.empty ()) + start_config = "sid-internal-warmup"; + Setting (dynamic_configurator, "start-config", start_config).write_to (w); + + // Connect the new-config pin of the dynamic configurator to + // the components of this board which need to know when the + // configuration changes. + assert (cpu); + Relation (cpu, "main", sess->main_obj).write_to (w); + if (! cpu->possibly_wrapped ()) + { + Relation (dynamic_configurator, "client", cpu).write_to (w); + } + if (gprof) + { + // gprof's configure! attribute will be set by the cpu. + Relation (gprof, "sim-sched", sess->sim_sched).write_to (w); + Relation (cpu, "gprof", gprof).write_to (w); + } + if (! gloss->possibly_wrapped ()) + { + Relation (dynamic_configurator, "client", gloss).write_to (w); + } + if (core_probe) + Relation (cpu, "core-probe", core_probe).write_to (w); + + // Connect the new-config pin of the dynamic configurator to any wrapped child components + dynamic_config_for_wrapped_children (dynamic_configurator, w); + + // Make the connections which enable the dynamic configurator to change configs on function + // call and return. + if (loader) + { + if (! loader->possibly_wrapped ()) + { + Relation (dynamic_configurator, "client", loader).write_to (w); + } + PinConnection (cpu, "cg-caller", dynamic_configurator, "function-caller!").write_to (w); + PinConnection (cpu, "cg-callee", dynamic_configurator, "function-callee!").write_to (w); + PinConnection (cpu, "cg-jump", dynamic_configurator, "function-jump!").write_to (w); + PinConnection (cpu, "cg-return", dynamic_configurator, "function-return!").write_to (w); + Relation (dynamic_configurator, "loader", loader).write_to (w); + PinConnection (dynamic_configurator, "function-address", loader, "function?").write_to (w); + } + + // Initialize the warmup functions and profile functions. + assert (! warmup_funcs.empty ()); + Setting (dynamic_configurator, "warmup-functions!", warmup_funcs).write_to (w); + if (! profile_funcs.empty ()) + Setting (dynamic_configurator, "profile-functions!", profile_funcs.substr (1)).write_to (w); // Skip the initial delimeter. } else { @@ -1113,7 +1438,6 @@ void BoardCfg::final_insn_count () { assert (cpu); assert (sess->shutdown_seq); - sess->shutdown_seq->add_output (0, cpu, "print-insn-summary!"); cpu->set (cpu, "final-insn-count?", "true"); } @@ -1208,3 +1532,33 @@ void BoardCfg::trace_core () core_probe->conn_bus (core_probe, "downstream", main_mapper, "access-port", false); core_probe->set (core_probe, "trace?", "true"); } + +void BoardCfg::add_profile_func (const string &spec) +{ + if (! spec.empty ()) + profile_funcs += "|" + spec; +} + +void BoardCfg::add_warmup_func (const string &funcs) +{ + if (! funcs.empty ()) + warmup_funcs += "," + funcs; +} + +void BoardCfg::set_warmup (bool w) +{ + if (w) + start_config = "sid-internal-warmup"; +} + +void BoardCfg::set_start_config (const string &config) +{ + if (! start_config.empty ()) + return; + + if (! config.empty ()) + { + start_config = "sid-internal-start-" + get_name (); + sess->profile_config (start_config + ":" + config.substr (1)); // get past leading comma + } +} diff --git a/sid/main/dynamic/commonCfg.h b/sid/main/dynamic/commonCfg.h index a95bcf4b7a..b2114db766 100644 --- a/sid/main/dynamic/commonCfg.h +++ b/sid/main/dynamic/commonCfg.h @@ -235,11 +235,26 @@ struct SessionCfg : AtomicCfg *tcl_bridge; bool verbose; bool use_stdio; + bool need_gprof; + bool need_core_probe; void add_ulog_file (const string filename); + map ulog_map; void add_gdb () { ++gdb_count; } void add_board (ComponentCfg *b) { ++board_count; add_child (b); } virtual void write_config (Writer &w); + // Support for dynamic configuration profiles + vector wrapped_components; + void add_wrapped_component (AtomicCfg *comp) { wrapped_components.push_back (comp); } + string wrap_config (); + void profile_config (const string &spec); +protected: + void add_profile_config (const string &name, const string &options); + void profile_config_error (const string &spec); + string profile_opt_value (const string& opt, const vector& opt_parts, unsigned max_parts); + string profile_opt_int_value (const string& opt, const vector& opt_parts); + string profile_opt_gprof_value (const string& opt, const vector& opt_parts); + bool match_profile_opt (const string &opt, const string& want, unsigned min_size); private: sid::host_int_4 board_count; sid::host_int_4 gdb_count; @@ -303,6 +318,9 @@ public: SessionCfg *sess, gprof_type type, int interval); + GprofCfg (const string name, + CpuCfg *cpu, + SessionCfg *sess); virtual ~GprofCfg (); }; @@ -356,6 +374,11 @@ public: virtual void trace_semantics (); virtual void trace_disassemble (); virtual void trace_core (); + virtual void set_warmup (bool w = true); + virtual void add_profile_func (const string &spec); + virtual void add_warmup_func (const string &funcs); + virtual void set_start_config (const string &config); + virtual void write_load (Writer &w); virtual void write_config (Writer &w); virtual ~BoardCfg (); @@ -365,6 +388,7 @@ public: CpuCfg *cpu; SessionCfg *sess; MapperCfg *main_mapper; + AtomicCfg *dynamic_configurator; protected: GdbCfg *gdb; @@ -374,6 +398,10 @@ public: AtomicCfg *icache; AtomicCfg *dcache; LoaderCfg *loader; + + string start_config; + string warmup_funcs; + string profile_funcs; }; #endif // __commonCfg_h__ diff --git a/sid/main/dynamic/mainDynamic.cxx b/sid/main/dynamic/mainDynamic.cxx index bd1fc95969..31b896bc5b 100644 --- a/sid/main/dynamic/mainDynamic.cxx +++ b/sid/main/dynamic/mainDynamic.cxx @@ -1,6 +1,6 @@ // mainDynamic.cxx - high-tech mainline. -*- C++ -*- -// Copyright (C) 1999-2004 Red Hat. +// Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 Red Hat. // This file is part of SID and is licensed under the GPL. // See the file COPYING.SID for conditions for redistribution. @@ -14,6 +14,8 @@ #include +#include + // Stub functions to set breakpoints on static void sid_pre_configure () {} static void sid_post_configure () {} @@ -68,6 +70,8 @@ usage () cout << "FILE names supplied without -f are done last, in sequence." << endl; cout << endl; cout << "--persistent Run top-level loop indefinitely" << endl; + cout << "--profile-config=NAME,OPTIONS" << endl; + cout << " Specify options for a named profiling configuration" << endl; cout << "--rc Pass stop code as simulator exit rc" << endl; cout << "--save-temps=FILE Write config to FILE, '-' for stdout." << endl; cout << "--wrap=COMPONENT Turn on SID API tracing for COMPONENT" << endl; @@ -120,10 +124,15 @@ usage () << " mmap Memory map given file" << endl << " latency=r:w Set read, write latencies [0:0]" << endl << " latency=rw Set both latencies [0]" << endl; + cout << "--profile-func=FUNCTIONS:NAME" << endl; + cout << " Specify functions which use a given profiling configuration" << endl; cout << "--ulog-level=LEVEL Set the logging level for the current board" << endl; cout << "--ulog-mode=less|match|equal" << endl << " Set the logging mode for the current board" << endl; cout << "--ulog-file=-|FILE Set the log file name" << endl; + cout << "--warmup Start the simulation in 'warm-up' mode" << endl; + cout << "--warmup-func=FUNCTIONS" << endl; + cout << " Specify functions to be simulated in 'warm-up' mode" << endl; cout << endl << " note: most board-specific options can be used in board-neutral position " << endl << " where they are interpreted as session-specific or default settings. " << endl; @@ -416,8 +425,12 @@ void try_add_gprof(const string optstring, BoardCfg *board) type = instruction_count; // default type value if (toks.size() > 1) // if we have a type argument { + if (toks[1].empty ()) + { + cerr << "error: unknown sub-option to --gprof: " << optstring << endl; + exit (21); + } vector subtoks = sidutil::tokenize (toks[1], "="); - if (subtoks[0] == "cycles") // If it is cycles { type = simulated_cycles; @@ -468,6 +481,10 @@ struct Defs { ulog_level (0), ulog_mode ("less"), ulog_file ("-"), + warmup (false), + profile_func (""), + warmup_func (""), + start_config (""), step_insn_count ("10000") {} string cpu; @@ -481,17 +498,29 @@ struct Defs { sid::host_int_4 ulog_level; string ulog_mode; string ulog_file; + bool warmup; + string profile_func; + string warmup_func; + string start_config; string step_insn_count; }; +struct BoardConfig +{ + BoardCfg *board; + string config; +}; -void need_sess (SessionCfg *&sess) +static void need_sess (SessionCfg *&sess, bool verbose) { if (! sess) - sess = new SessionCfg (""); + { + sess = new SessionCfg (""); + sess->profile_config ("sid-internal-warmup:"); + sess->verbose = verbose; + } } - // main line int main(int argc, char* argv[]) @@ -504,6 +533,7 @@ main(int argc, char* argv[]) string output_file (""); SessionCfg *sess = NULL; BoardCfg *curr_board = NULL; + vector board_configs; int nboards = 0; if (argc == 1) @@ -518,13 +548,16 @@ main(int argc, char* argv[]) enum option_num { opt_help, opt_version, opt_save_temps, opt_wrap, opt_verbose, opt_tksched, opt_enable_warnings, - opt_persistent, opt_rc, opt_no_run, opt_sidrtc, opt_sidcodec, + opt_persistent, opt_profile_config, + opt_rc, opt_no_run, opt_sidrtc, opt_sidcodec, opt_tksm, opt_board, opt_cpu, opt_gdb, opt_gloss, opt_engine, opt_insn_count, opt_load, opt_icache, opt_dcache, - opt_memory_region, opt_trace_extract, opt_trace_semantics, + opt_memory_region, opt_profile_func, + opt_trace_extract, opt_trace_semantics, opt_trace_disassemble, opt_trace_counter, opt_trace_core, opt_final_insn_count, opt_eb, opt_el, opt_gprof, - opt_ulog_level, opt_ulog_mode, opt_ulog_file }; + opt_ulog_level, opt_ulog_mode, opt_ulog_file, + opt_warmup, opt_warmup_func }; int curr_opt; @@ -543,6 +576,7 @@ main(int argc, char* argv[]) {"tksched", no_argument, & curr_opt, opt_tksched }, {"enable-warnings", no_argument, & curr_opt, opt_enable_warnings }, {"persistent", no_argument, & curr_opt, opt_persistent }, + {"profile-config", required_argument, &curr_opt, opt_profile_config }, {"rc", no_argument, & curr_opt, opt_rc }, {"tksm", no_argument, & curr_opt, opt_tksm }, @@ -561,6 +595,7 @@ main(int argc, char* argv[]) {"dcache", required_argument, & curr_opt, opt_dcache }, {"memory-region", required_argument, & curr_opt, opt_memory_region }, {"gloss", no_argument, & curr_opt, opt_gloss }, + {"profile-func", required_argument, &curr_opt, opt_profile_func }, {"trace-extract", no_argument, & curr_opt, opt_trace_extract }, {"trace-semantics", no_argument, & curr_opt, opt_trace_semantics }, {"trace-disassemble", no_argument, & curr_opt, opt_trace_disassemble }, @@ -572,9 +607,13 @@ main(int argc, char* argv[]) {"ulog-level", required_argument, &curr_opt, opt_ulog_level }, {"ulog-mode", required_argument, &curr_opt, opt_ulog_mode }, {"ulog-file", required_argument, &curr_opt, opt_ulog_file }, + {"warmup", no_argument, &curr_opt, opt_warmup }, + {"warmup-func", required_argument, &curr_opt, opt_warmup_func }, { 0, 0, NULL, 0 } }; - + + string board_start_config = ""; + string wrap_config = ""; while (true) { int c = getopt_long (argc, argv, "+hvne:f:", @@ -615,9 +654,17 @@ main(int argc, char* argv[]) case opt_board: { - need_sess (sess); + need_sess (sess, verbose_p); if (curr_board) - sess->add_board (curr_board); + { + sess->add_board (curr_board); + if (! defaults.warmup) + { + BoardConfig bc = { curr_board, defaults.start_config + board_start_config }; + board_configs.push_back (bc); + } + board_start_config = ""; + } curr_board = NULL; string new_board_type = optstring(); string new_board_name (new_board_type + "-" + @@ -648,6 +695,9 @@ main(int argc, char* argv[]) curr_board->set_ulog_level (defaults.ulog_level); curr_board->set_ulog_mode (defaults.ulog_mode); curr_board->set_ulog_file (defaults.ulog_file); + curr_board->set_warmup (defaults.warmup); + curr_board->add_warmup_func (defaults.warmup_func); + curr_board->add_profile_func (defaults.profile_func); if (defaults.step_insn_count != "10000") curr_board->set_step_insn_count(defaults.step_insn_count); break; @@ -676,11 +726,13 @@ main(int argc, char* argv[]) verbose_p = true; if (sess) sess->verbose = true; + defaults.start_config += " --verbose"; break; case opt_gprof: option_requires_board (curr_board, "gprof"); try_add_gprof(optstring(), curr_board); + board_start_config += " --gprof=" + optstring(); break; case opt_gdb: @@ -695,7 +747,7 @@ main(int argc, char* argv[]) break; case opt_load: - need_sess (sess); + need_sess (sess, verbose_p); try_load_file (optstring(), curr_board, sess); break; @@ -708,44 +760,80 @@ main(int argc, char* argv[]) case opt_trace_extract: if (curr_board) - curr_board->trace_extract(); + { + board_start_config += " --trace-extract"; + curr_board->trace_extract(); + } else - defaults.trace_extract = true; + { + defaults.trace_extract = true; + defaults.start_config += " --trace-extract"; + } break; case opt_trace_semantics: if (curr_board) - curr_board->trace_semantics(); + { + board_start_config += " --trace-semantics"; + curr_board->trace_semantics(); + } else - defaults.trace_semantics = true; + { + defaults.trace_semantics = true; + defaults.start_config += " --trace-semantics"; + } break; case opt_trace_disassemble: if (curr_board) - curr_board->trace_disassemble(); + { + curr_board->trace_disassemble(); + board_start_config += " --trace-disassemble"; + } else - defaults.trace_disassemble = true; + { + defaults.trace_disassemble = true; + defaults.start_config += " --trace-disassemble"; + } break; case opt_trace_counter: if (curr_board) - curr_board->trace_counter(); + { + curr_board->trace_counter(); + board_start_config += " --trace-counter"; + } else - defaults.trace_counter = true; + { + defaults.trace_counter = true; + defaults.start_config += " --trace-counter"; + } break; case opt_final_insn_count: if (curr_board) - curr_board->final_insn_count(); + { + curr_board->final_insn_count(); + board_start_config += " --final-insn-count"; + } else - defaults.final_insn_count = true; + { + defaults.final_insn_count = true; + defaults.start_config += " --final-insn-count"; + } break; case opt_trace_core: if (curr_board) - curr_board->trace_core(); + { + curr_board->trace_core(); + board_start_config += " --trace-core"; + } else - defaults.trace_core = true; + { + defaults.trace_core = true; + defaults.start_config += " --trace-core"; + } break; case opt_enable_warnings: @@ -760,20 +848,28 @@ main(int argc, char* argv[]) string c (optstring()); if (sess) sess->use_tcl_bridge (); - if (! AtomicCfg::wrap_component (c)) + AtomicCfg *comp = AtomicCfg::wrap_component (c); + if (! comp) { cerr << "error: no component named '" << c << "' to wrap" << endl; exit (9); } + sess->add_wrapped_component (comp); } break; case opt_insn_count: if (curr_board) - curr_board->set_step_insn_count(optstring()); + { + curr_board->set_step_insn_count(optstring()); + board_start_config += " --insn-count=" + optstring(); + } else - defaults.step_insn_count = optstring(); + { + defaults.step_insn_count = optstring(); + defaults.start_config += " --insn-count=" + optstring(); + } break; case opt_persistent: @@ -805,7 +901,7 @@ main(int argc, char* argv[]) break; case opt_memory_region: - need_sess (sess); + need_sess (sess, verbose_p); try_add_memory (optstring(), curr_board, sess); break; @@ -835,28 +931,36 @@ main(int argc, char* argv[]) case opt_ulog_level: if (curr_board) - curr_board->set_ulog_level (optaddr ("ulog-level")); + { + curr_board->set_ulog_level (optaddr ("ulog-level")); + board_start_config += " --ulog-level=" + optstring(); + } else { defaults.ulog_level = optaddr ("ulog-level"); - need_sess (sess); + defaults.start_config += " --ulog-level=" + optstring(); + need_sess (sess, verbose_p); sess->set_ulog_level (optaddr ("ulog-level")); } break; case opt_ulog_mode: if (curr_board) - curr_board->set_ulog_mode (optstring ()); + { + curr_board->set_ulog_mode (optstring ()); + board_start_config += " --ulog-mode=" + optstring(); + } else { defaults.ulog_mode = optstring (); - need_sess (sess); + defaults.start_config += " --ulog-mode=" + optstring(); + need_sess (sess, verbose_p); sess->set_ulog_mode (optstring ()); } break; case opt_ulog_file: - need_sess (sess); + need_sess (sess, verbose_p); sess->add_ulog_file (optstring ()); if (curr_board) curr_board->set_ulog_file (optstring ()); @@ -866,9 +970,43 @@ main(int argc, char* argv[]) sess->set_ulog_file (optstring ()); } break; + + case opt_warmup: + if (curr_board) + curr_board->set_warmup (true); + else + defaults.warmup = true; + break; + + case opt_warmup_func: + if (curr_board) + curr_board->add_warmup_func (optstring ()); + else + { + if (! defaults.warmup_func.empty ()) + defaults.warmup_func += ","; + defaults.warmup_func += optstring (); + } + break; + + case opt_profile_func: + if (curr_board) + curr_board->add_profile_func (optstring ()); + else + { + if (! defaults.profile_func.empty ()) + defaults.profile_func += "|"; + defaults.profile_func += optstring (); + } + break; + + case opt_profile_config: + need_sess (sess, verbose_p); + sess->profile_config (optstring ()); + break; } break; - + case '?': default: @@ -878,7 +1016,20 @@ main(int argc, char* argv[]) } if (sess && curr_board) - sess->add_board (curr_board); + { + sess->add_board (curr_board); + if (! defaults.warmup) + { + BoardConfig bc = { curr_board, defaults.start_config + board_start_config }; + board_configs.push_back (bc); + + string wrap_config = sess->wrap_config (); + for (vector::const_iterator it = board_configs.begin (); + it != board_configs.end (); + ++it) + it->board->set_start_config (it->config + wrap_config); + } + } if (persistent_p) config_items.push_back (make_pair (false, string("set main persistent? true"))); -- 2.11.0