From 886a56f08bd37f20247525826d05dc9ddd988c78 Mon Sep 17 00:00:00 2001 From: Germain Haugou Date: Fri, 4 Feb 2022 15:39:18 +0100 Subject: [PATCH] [POWER] Several fixed for power models --- engine/include/gv/power.hpp | 75 ++++++++++++++++++++--- engine/include/vp/component.hpp | 10 +++ engine/include/vp/power/power_source.hpp | 61 +++++++++++++----- engine/include/vp/power/power_trace.hpp | 32 +++++++--- engine/src/launcher.cpp | 12 ++-- engine/src/power/component_power.cpp | 53 ++++++++++++++++ engine/src/power/power_engine.cpp | 24 ++++++-- engine/src/power/power_source.cpp | 56 +++++++++++++++-- engine/src/power/power_trace.cpp | 74 ++++++++++++---------- engine/src/vp.cpp | 30 ++++++--- models/cpu/iss/vp/include/iss_wrapper.hpp | 4 +- models/cpu/iss/vp/src/iss_wrapper.cpp | 13 +++- models/memory/memory_impl.cpp | 25 ++------ models/utils/composite_impl.cpp | 5 ++ 14 files changed, 360 insertions(+), 114 deletions(-) diff --git a/engine/include/gv/power.hpp b/engine/include/gv/power.hpp index df4853d..2f43e60 100644 --- a/engine/include/gv/power.hpp +++ b/engine/include/gv/power.hpp @@ -148,9 +148,41 @@ namespace vp */ void setup(double temp, double volt, double freq); + /** + * @brief Turn on a power source + * + * This power source should be turned on when its power domain is turned on, in order to start consuming power + */ + void turn_on(); + + /** + * @brief Turn off a power source + * + * This power source should be turned off when its power domain is turned off, in order to stop consuming power + */ + void turn_off(); + + /** + * @brief Turn on a power source + * + * This power source should be turned on when its power domain is turned on, in order to start consuming power + */ + void turn_dynamic_power_on(); + + /** + * @brief Turn off a power source + * + * This power source should be turned off when its power domain is turned off, in order to stop consuming power + */ + void turn_dynamic_power_off(); + private: - Linear_table *table = NULL; // Table of power values for all supported temperatures and voltages - // imported from the json configuration given when trace was initialized. + void check(); + + Linear_table *dyn_table = NULL; // Table of power values for all supported temperatures and voltages + // imported from the json configuration given when trace was initialized. + Linear_table *leakage_table = NULL; // Table of power values for all supported temperatures and voltages + // imported from the json configuration given when trace was initialized. double quantum; // Current quantumm of energy, for quantum-based power consumption. // The current value is estimated depending on voltage and temperature according // to the provided json configuration. @@ -162,7 +194,12 @@ namespace vp // to the provided json configuration. component *top; // Top component containing the power source power_trace *trace; // Power trace where the power consumption should be reported. - bool is_on = false; // True is the source is on and backgroun-power and leakage should be reported + bool is_dynamic_power_started = false; // True is the source consuming dynamic backgroun power + bool is_leakage_power_started = false; // True is the source should start consuming leakage power + bool is_on = false; // True is the power domain containing the power source is on and backgroun-power and leakage should be reported + bool is_dynamic_power_on = false; // True is the power domain containing the power source is on and backgroun-power and leakage should be reported + bool dynamic_power_is_on_sync = false; + bool leakage_power_is_on_sync = false; }; @@ -327,12 +364,16 @@ namespace vp // power consumed. void account_leakage_power(); - // Check if the current amount of cycle energy is not for the current cycle + // Check if the current amount of power due to quantum of energies + // is not for the current cycle // (by checking the timestamp), and if not, reset it to zero. - inline void flush_dynamic_energy_for_cycle(); + inline void flush_quantum_power_for_cycle(); - // Get the amount of energy spent in the current cycle - inline double get_dynamic_energy_for_cycle(); + // Get the average power of the current cycle due to quantums of energy + inline double get_quantum_power_for_cycle(); + + // Get the energy spent in the current cycle due to quantums of energy + inline double get_quantum_energy_for_cycle(); // Return the total amount of dynamic energy spent since the beginning // of the report windows (since report_start was called) @@ -363,7 +404,7 @@ namespace vp int64_t curent_cycle_timestamp; // Timestamp of the current cycle, used to compute energy spent in the // current cycle. As soon as current time is different, the timestamp // is set to current time and the current energy is set to 0. - double dynamic_energy_for_cycle; // Amount of energy spent in the current cycle. + double quantum_power_for_cycle; // Power spent by quentum of energy in the current cycle. // It is increased everytime a quantum of energy is // spent and reset to zero when the current cycle is // over. It is mostly used to compute the instant power @@ -468,6 +509,15 @@ namespace vp */ vp::power::power_trace *get_power_trace() { return &this->power_trace; } + /** + * @brief Set power supply state + * + * This sets the power supply for this component and all his childs. + * + * @param state Supply state + */ + void power_supply_set_all(int state); + protected: /** * @brief Get the report energy from childs object @@ -516,10 +566,15 @@ namespace vp // Get instant power for this component and the whole hierarchy below him. double get_power_from_self_and_childs(); + // Set power supply state + static void power_supply_sync(void *_this, int state); + component ⊤ // Component containing the power component object vp::power::power_trace power_trace; // Default power trace of this component std::vector traces; // Vector of power traces of this component + std::vector sources; // Vector of power sources of this component power::engine *engine = NULL; // Power engine + vp::wire_slave power_port; // Slave port for setting power supply state }; @@ -542,6 +597,8 @@ namespace vp */ engine(vp::component *top); + ~engine(); + /** * @brief Start power report generation * @@ -570,6 +627,8 @@ namespace vp std::vector traces; // Vector of all traces. vp::component *top; // Top component of the simulated architecture + + FILE *file; // File where the power reports are dumped }; }; diff --git a/engine/include/vp/component.hpp b/engine/include/vp/component.hpp index dd336a5..44b0507 100644 --- a/engine/include/vp/component.hpp +++ b/engine/include/vp/component.hpp @@ -397,6 +397,7 @@ namespace vp { { friend class component_clock; + friend class vp::power::component_power; public: component(js::config *config); @@ -410,6 +411,7 @@ namespace vp { virtual void quit(int status) {} virtual void pre_reset() {} virtual void reset(bool active) {} + virtual void power_supply_set(int state) {} virtual void load() {} virtual void elab(); virtual void run() {} @@ -568,6 +570,14 @@ namespace vp { vp::component *__gv_create(std::string config_path, struct gv_conf *gv_conf); + class top + { + public: + component *top_instance; + power::engine *power_engine; + private: + }; + }; #endif diff --git a/engine/include/vp/power/power_source.hpp b/engine/include/vp/power/power_source.hpp index 10bb994..bcea94c 100644 --- a/engine/include/vp/power/power_source.hpp +++ b/engine/include/vp/power/power_source.hpp @@ -25,51 +25,78 @@ #include "vp/vp_data.hpp" +inline void vp::power::power_source::turn_on() +{ + this->is_on = true; + this->is_dynamic_power_on = true; + this->check(); +} + + +inline void vp::power::power_source::turn_off() +{ + this->is_on = false; + this->is_dynamic_power_on = false; + this->check(); +} + +inline void vp::power::power_source::turn_dynamic_power_on() +{ + this->is_dynamic_power_on = true; + this->check(); +} + +inline void vp::power::power_source::turn_dynamic_power_off() +{ + this->is_dynamic_power_on = false; + this->check(); +} + inline void vp::power::power_source::leakage_power_start() { - // Only start accounting leakage if not already done and if leakage is defined - if (!this->is_on && this->leakage != -1) + // Only start if leakage is defined + if (this->leakage != -1) { - this->trace->inc_leakage_power(this->leakage); + this->is_leakage_power_started = true; + this->check(); } - this->is_on = true; } inline void vp::power::power_source::leakage_power_stop() { - // Only stop accounting leakage if not already done and if leakage is defined - if (this->is_on && this->leakage != -1) + // Only stop if leakage is defined + if (this->leakage != -1) { - this->trace->inc_leakage_power(-this->leakage); + this->is_leakage_power_started = false; + this->check(); } - this->is_on = false; } inline void vp::power::power_source::dynamic_power_start() { - // Only start accounting background power if not already done and if it is is defined - if (!this->is_on && this->background_power != -1) + // Only start accounting background power if it is is defined + if (this->background_power != -1) { - this->trace->inc_dynamic_power(this->background_power); + this->is_dynamic_power_started = true; + this->check(); } - this->is_on = true; } inline void vp::power::power_source::dynamic_power_stop() { - // Only stop accounting background power if not already done and if it is is defined - if (this->is_on && this->background_power != -1) + // Only stop accounting background power if it is is defined + if (this->background_power != -1) { - this->trace->inc_dynamic_power(-this->background_power); + this->is_dynamic_power_started = false; + this->check(); } - this->is_on = false; } @@ -77,7 +104,7 @@ inline void vp::power::power_source::dynamic_power_stop() inline void vp::power::power_source::account_energy_quantum() { // Only account energy is a quantum is defined - if (this->quantum != -1) + if (this->is_on && this->is_dynamic_power_on && this->quantum != -1) { this->trace->inc_dynamic_energy(this->quantum); } diff --git a/engine/include/vp/power/power_trace.hpp b/engine/include/vp/power/power_trace.hpp index 6d83359..fe33eaa 100644 --- a/engine/include/vp/power/power_trace.hpp +++ b/engine/include/vp/power/power_trace.hpp @@ -32,25 +32,43 @@ inline double vp::power::power_trace::get_power() -inline double vp::power::power_trace::get_dynamic_energy_for_cycle() +inline double vp::power::power_trace::get_quantum_power_for_cycle() { // First check if the current energy is for an old cycle - this->flush_dynamic_energy_for_cycle(); + this->flush_quantum_power_for_cycle(); // And return the current total - return this->dynamic_energy_for_cycle; + return this->quantum_power_for_cycle; } +inline double vp::power::power_trace::get_quantum_energy_for_cycle() +{ + double power = this->get_quantum_power_for_cycle(); -inline void vp::power::power_trace::flush_dynamic_energy_for_cycle() + if (power != 0) + { + return power * this->top->get_period(); + } + + return 0; +} + + + +inline void vp::power::power_trace::flush_quantum_power_for_cycle() { // Clear the current total if it is not for the current cycle - if (this->curent_cycle_timestamp < this->top->get_time()) + if (this->quantum_power_for_cycle && this->curent_cycle_timestamp < this->top->get_time()) { - this->curent_cycle_timestamp = this->top->get_time(); - this->dynamic_energy_for_cycle = 0; + if (this->parent) + { + this->parent->inc_dynamic_power(-this->quantum_power_for_cycle); + } + this->quantum_power_for_cycle = 0; } + + this->curent_cycle_timestamp = this->top->get_time(); } diff --git a/engine/src/launcher.cpp b/engine/src/launcher.cpp index 6390885..ad40096 100644 --- a/engine/src/launcher.cpp +++ b/engine/src/launcher.cpp @@ -43,6 +43,7 @@ class Gvsoc_launcher : public gv::Gvsoc private: + void *handler; vp::component *instance; }; @@ -53,19 +54,20 @@ gv::Gvsoc *gv::gvsoc_new() void Gvsoc_launcher::open(std::string config_path) { - this->instance = vp::__gv_create(config_path, NULL); + this->handler = vp::__gv_create(config_path, NULL); + this->instance = ((vp::top *)this->handler)->top_instance; - gv_start((void *)this->instance); + gv_start(this->handler); } void Gvsoc_launcher::close() { - gv_destroy((void *)this->instance); + gv_destroy(this->handler); } void Gvsoc_launcher::run() { - gv_step((void *)this->instance, 0); + gv_step(this->handler, 0); } int64_t Gvsoc_launcher::stop() @@ -76,7 +78,7 @@ int64_t Gvsoc_launcher::stop() int64_t Gvsoc_launcher::step(int64_t duration) { - gv_step((void *)this->instance, duration); + gv_step(this->handler, duration); return 0; } diff --git a/engine/src/power/component_power.cpp b/engine/src/power/component_power.cpp index 310a00b..d8930b9 100644 --- a/engine/src/power/component_power.cpp +++ b/engine/src/power/component_power.cpp @@ -41,6 +41,9 @@ void vp::power::component_power::build() { this->get_engine()->reg_trace(trace); } + + this->power_port.set_sync_meth(&vp::power::component_power::power_supply_sync); + this->top.new_slave_port(this, "power_supply", &this->power_port); } @@ -69,6 +72,8 @@ int vp::power::component_power::new_power_source(std::string name, power_source source->setup(VP_POWER_DEFAULT_TEMP, VP_POWER_DEFAULT_VOLT, VP_POWER_DEFAULT_FREQ); + this->sources.push_back(source); + return 0; } @@ -150,3 +155,51 @@ void vp::power::component_power::dump_child_traces(FILE *file, double total) x->power.dump(file, total); } } + +void vp::power::component_power::power_supply_sync(void *__this, int state) +{ + vp::power::component_power *_this = (vp::power::component_power *)__this; + _this->power_supply_set_all(state); +} + + +void vp::power::component_power::power_supply_set_all(int state) +{ + this->top.power_supply_set(state); + + for (auto &x : this->top.childs) + { + x->power.power_supply_set_all(state); + } + + + + if (state >= 2) + { + for (auto &x : this->sources) + { + if (state == 3) + { + x->turn_dynamic_power_on(); + } + else + { + x->turn_dynamic_power_off(); + } + } + } + else + { + for (auto &x : this->sources) + { + if (state == 1) + { + x->turn_on(); + } + else + { + x->turn_off(); + } + } + } +} diff --git a/engine/src/power/power_engine.cpp b/engine/src/power/power_engine.cpp index c7661f6..19652c0 100644 --- a/engine/src/power/power_engine.cpp +++ b/engine/src/power/power_engine.cpp @@ -46,14 +46,11 @@ void vp::power::engine::start_capture() void vp::power::engine::stop_capture() { // When stopping, dump recursively all traces to a file - FILE *file = fopen("power_report.csv", "w"); - if (file == NULL) + + if (this->file) { - // vp_warning_always(&this->warning, "Failed to open power report file (path: %s)\n", "power_report.csv"); - return; + this->top->dump_traces_recursive(file); } - - this->top->dump_traces_recursive(file); } @@ -64,4 +61,19 @@ vp::power::engine::engine(vp::component *top) // Declare power service, each component will ask the connection to it top->new_service("power", this); + + this->file = fopen("power_report.csv", "w"); + if (this->file == NULL) + { + //vp_warning_always(&this->warning, "Failed to open power report file (path: %s)\n", "power_report.csv"); + } +} + + +vp::power::engine::~engine() +{ + if (this->file) + { + fclose(this->file); + } } diff --git a/engine/src/power/power_source.cpp b/engine/src/power/power_source.cpp index 579e27f..c28ded0 100644 --- a/engine/src/power/power_source.cpp +++ b/engine/src/power/power_source.cpp @@ -30,15 +30,15 @@ void vp::power::power_source::setup(double temp, double volt, double freq) // dynamic background power or leakage if they are defined, which is the case if they are not -1 if (this->quantum != -1) { - this->quantum = this->table->get(temp, volt, freq); + this->quantum = this->dyn_table->get(temp, volt, freq); } if (this->background_power != -1) { - this->background_power = this->table->get(temp, volt, freq); + this->background_power = this->dyn_table->get(temp, volt, freq); } if (this->leakage != -1) { - this->leakage = this->table->get(temp, volt, freq); + this->leakage = this->leakage_table->get(temp, volt, freq); } } @@ -130,7 +130,14 @@ int vp::power::power_source::init(component *top, std::string name, js::config * return -1; } - this->table = new Linear_table(values); + if (is_leakage) + { + this->leakage_table = new Linear_table(values); + } + else + { + this->dyn_table = new Linear_table(values); + } } else { @@ -147,3 +154,44 @@ int vp::power::power_source::init(component *top, std::string name, js::config * return 0; } + + +void vp::power::power_source::check() +{ + bool leakage_power_is_on = this->is_on && this->is_leakage_power_started; + bool dynamic_power_is_on = this->is_on && this->is_dynamic_power_on && this->is_dynamic_power_started; + + if (this->dynamic_power_is_on_sync != dynamic_power_is_on) + { + if (this->background_power) + { + if (dynamic_power_is_on) + { + this->trace->inc_dynamic_power(this->background_power); + } + else + { + this->trace->inc_dynamic_power(-this->background_power); + } + } + + this->dynamic_power_is_on_sync = dynamic_power_is_on; + } + + if (this->leakage_power_is_on_sync != leakage_power_is_on) + { + if (this->leakage) + { + if (leakage_power_is_on) + { + this->trace->inc_leakage_power(this->leakage); + } + else + { + this->trace->inc_leakage_power(-this->leakage); + } + } + + this->leakage_power_is_on_sync = leakage_power_is_on; + } +} diff --git a/engine/src/power/power_trace.cpp b/engine/src/power/power_trace.cpp index 3bda6a8..a69aeac 100644 --- a/engine/src/power/power_trace.cpp +++ b/engine/src/power/power_trace.cpp @@ -28,7 +28,7 @@ int vp::power::power_trace::init(component *top, std::string name, vp::power::po { this->top = top; top->traces.new_trace_event_real(name, &this->trace); - this->dynamic_energy_for_cycle = 0; + this->quantum_power_for_cycle = 0; this->report_dynamic_energy = 0; this->report_leakage_energy = 0; this->curent_cycle_timestamp = 0; @@ -37,7 +37,7 @@ int vp::power::power_trace::init(component *top, std::string name, vp::power::po if (parent == NULL) { vp::component *component = top->get_parent(); - if (component) + if (component && component->get_path() != "") { parent = component->power.get_power_trace(); } @@ -73,10 +73,13 @@ void vp::power::power_trace::trace_handler(void *__this, vp::clock_event *event) void vp::power::power_trace::report_start() { + this->account_dynamic_power(); + this->account_leakage_power(); + // Since the report start may be triggered in the middle of several events // for power consumptions, include what has already be accounted // in the same cycle. - this->report_dynamic_energy = this->get_dynamic_energy_for_cycle(); + this->report_dynamic_energy = this->get_quantum_energy_for_cycle(); this->report_leakage_energy = 0; this->report_start_timestamp = this->top->get_time(); } @@ -96,9 +99,8 @@ void vp::power::power_trace::get_report_power(double *dynamic, double *leakage) double childs_dynamic = 0, childs_leakage = 0; // To get the power on the report window, we just get the total energy and divide by the window duration - this->top->power.get_report_energy_from_childs(&childs_dynamic, &childs_leakage); - *dynamic = (childs_dynamic + this->get_report_dynamic_energy()) / (this->top->get_time() - this->report_start_timestamp); - *leakage = (childs_leakage + this->get_report_leakage_energy()) / (this->top->get_time() - this->report_start_timestamp); + *dynamic = (this->get_report_dynamic_energy()) / (this->top->get_time() - this->report_start_timestamp); + *leakage = (this->get_report_leakage_energy()) / (this->top->get_time() - this->report_start_timestamp); } @@ -127,43 +129,25 @@ void vp::power::power_trace::dump_vcd_trace() if (this->top->get_path() == "") return; - double power = 0.0; - // To dump the VCD trace, we need to compute the instant power, since this is what is reported. // This is easy for background and leakage power. For enery quantum, we get the amount of energy for the current // cycle and compute the instant power using the clock engine period. - // Some component do not have clocks. They cannot use energy quantum but they can still use background - // power and leakage - if (this->top->get_clock()) - { - int64_t period = this->top->get_period(); - if (period != 0) - { - power += this->get_dynamic_energy_for_cycle() / period; - } - } + double quantum_power = this->get_quantum_power_for_cycle(); double power_background = this->current_dynamic_power + this->current_leakage_power; // Also account the power from childs since VCD traces are hierarchical - double childs_power = this->top->power.get_power_from_childs(); - this->current_power = power + power_background + childs_power; + this->current_power = quantum_power + power_background; // Dump the instant power to trace this->trace.event_real(current_power); // If there was a contribution from energy quantum, schedule an event in the next cycle so that we dump again // the trace since teh quantum implicitely disappears and overal power is modified - if (!this->trace_event->is_enqueued() && power > 0) + if (!this->trace_event->is_enqueued() && quantum_power > 0) { this->top->event_enqueue(this->trace_event, 1); } - - // Notify the parent that this trace was dumped so that the upper traces can be dumped as well - if (this->parent) - { - this->parent->dump_vcd_trace(); - } } @@ -213,15 +197,26 @@ void vp::power::power_trace::account_leakage_power() void vp::power::power_trace::inc_dynamic_energy(double quantum) { + if (this->top->get_period() == 0) + { + return; + } + // Since we need to account the energy for the current amount of the cycle, check if it needs to be flushed - this->flush_dynamic_energy_for_cycle(); + this->flush_quantum_power_for_cycle(); // Then account it to both the total amount and to the cycle amount - this->dynamic_energy_for_cycle += quantum; + double power = quantum / this->top->get_period(); + this->quantum_power_for_cycle += power; this->report_dynamic_energy += quantum; - // Redump VCD trace since teh instant power is impacted + // Redump VCD trace since the instant power is impacted this->dump_vcd_trace(); + + if (this->parent) + { + this->parent->inc_dynamic_power(power); + } } @@ -235,14 +230,24 @@ void vp::power::power_trace::inc_dynamic_power(double power_incr) this->account_dynamic_power(); this->current_dynamic_power += power_incr; - // Redump VCD trace since teh instant power is impacted + // Redump VCD trace since the instant power is impacted this->dump_vcd_trace(); + + if (this->parent) + { + this->parent->inc_dynamic_power(power_incr); + } } void vp::power::power_trace::inc_leakage_power(double power_incr) { + // TODO this is wasting time and should be removed once fake component such as time domain and trace domain + // are not in the component hierarchy anymore + if (this->top->get_path() == "") + return; + // Leakage and dynamic are handled differently since they are reported separately, // In both cases, first compute the power on current period, start a new one, // and change the power so that it is constant over the period, to properly @@ -250,6 +255,11 @@ void vp::power::power_trace::inc_leakage_power(double power_incr) this->account_leakage_power(); this->current_leakage_power += power_incr; - // Redump VCD trace since teh instant power is impacted + // Redump VCD trace since the instant power is impacted this->dump_vcd_trace(); + + if (this->parent) + { + this->parent->inc_leakage_power(power_incr); + } } diff --git a/engine/src/vp.cpp b/engine/src/vp.cpp index 271e007..36329a6 100644 --- a/engine/src/vp.cpp +++ b/engine/src/vp.cpp @@ -67,6 +67,7 @@ char vp_error[VP_ERROR_SIZE]; static Gv_proxy *proxy = NULL; + uint64_t vp::reg::get_field(int offset, int width) { uint64_t value = 0; @@ -329,6 +330,7 @@ void vp::component_clock::clk_reg(component *_this, component *clock) } } + void vp::component::reset_all(bool active, bool from_itf) { // Small hack to not propagate the reset from top level if the reset has @@ -1686,12 +1688,15 @@ vp::component *vp::__gv_create(std::string config_path, struct gv_conf *gv_conf) vp::component *instance = constructor(js_config); - new vp::power::engine(instance); + vp::top *top = new vp::top(); + + top->top_instance = instance; + top->power_engine = new vp::power::engine(instance); instance->set_vp_config(gv_config); instance->set_gv_conf(gv_conf); - return instance; + return (vp::component *)top; } @@ -1708,7 +1713,8 @@ extern "C" void gv_destroy(void *arg) extern "C" void gv_start(void *arg) { - vp::component *instance = (vp::component *)arg; + vp::top *top = (vp::top *)arg; + vp::component *instance = (vp::component *)top->top_instance; instance->pre_pre_build(); instance->pre_build(); @@ -1736,7 +1742,8 @@ extern "C" void gv_start(void *arg) extern "C" void gv_step(void *arg, int64_t timestamp) { - vp::component *instance = (vp::component *)arg; + vp::top *top = (vp::top *)arg; + vp::component *instance = (vp::component *)top->top_instance; instance->step(timestamp); } @@ -1744,7 +1751,8 @@ extern "C" void gv_step(void *arg, int64_t timestamp) extern "C" int64_t gv_time(void *arg) { - vp::component *instance = (vp::component *)arg; + vp::top *top = (vp::top *)arg; + vp::component *instance = (vp::component *)top->top_instance; return instance->get_time_engine()->get_next_event_time(); } @@ -1989,9 +1997,10 @@ vp::time_event *vp::time_scheduler::enqueue(time_event *event, int64_t time) -extern "C" int gv_run(void *_instance) +extern "C" int gv_run(void *arg) { - vp::component *instance = (vp::component *)_instance; + vp::top *top = (vp::top *)arg; + vp::component *instance = (vp::component *)top->top_instance; if (!proxy) { @@ -2014,9 +2023,10 @@ extern "C" void gv_init(struct gv_conf *gv_conf) } -extern "C" void gv_stop(void *_instance, int retval) +extern "C" void gv_stop(void *arg, int retval) { - vp::component *instance = (vp::component *)_instance; + vp::top *top = (vp::top *)arg; + vp::component *instance = (vp::component *)top->top_instance; if (proxy) { @@ -2024,6 +2034,8 @@ extern "C" void gv_stop(void *_instance, int retval) } instance->stop(); + + delete top->power_engine; } diff --git a/models/cpu/iss/vp/include/iss_wrapper.hpp b/models/cpu/iss/vp/include/iss_wrapper.hpp index f7e234e..9ae3c3f 100644 --- a/models/cpu/iss/vp/include/iss_wrapper.hpp +++ b/models/cpu/iss/vp/include/iss_wrapper.hpp @@ -113,6 +113,7 @@ class iss_wrapper : public vp::component, vp::Gdbserver_core vp::wire_slave irq_req_itf; vp::wire_master irq_ack_itf; + vp::wire_master busy_itf; vp::wire_master flush_cache_req_itf; vp::wire_slave flush_cache_ack_itf; @@ -142,8 +143,7 @@ class iss_wrapper : public vp::component, vp::Gdbserver_core vp::reg_1 do_step; std::vector insn_groups_power; - vp::power::power_source clock_gated_power; - vp::power::power_source leakage_power; + vp::power::power_source background_power; vp::trace state_event; vp::trace pc_trace_event; diff --git a/models/cpu/iss/vp/src/iss_wrapper.cpp b/models/cpu/iss/vp/src/iss_wrapper.cpp index 69df9a4..c535b83 100644 --- a/models/cpu/iss/vp/src/iss_wrapper.cpp +++ b/models/cpu/iss/vp/src/iss_wrapper.cpp @@ -287,6 +287,11 @@ void iss_wrapper::clock_sync(void *__this, bool active) _this->clock_active = active; + if (_this->busy_itf.is_bound()) + { + _this->busy_itf.sync(active); + } + // TODO this could be better handler is the clock would be taken into // account in the core state machine uint8_t value = active && _this->is_active_reg.get(); @@ -1330,8 +1335,7 @@ int iss_wrapper::build() this->insn_groups_power.resize(1); power.new_power_source("power_insn", &this->insn_groups_power[0], this->get_js_config()->get("**/insn")); } - power.new_power_source("power_clock_gated", &clock_gated_power, this->get_js_config()->get("**/clock_gated")); - power.new_power_source("leakage", &leakage_power, this->get_js_config()->get("**/leakage")); + power.new_power_source("background", &background_power, this->get_js_config()->get("**/power_models/background")); data.set_resp_meth(&iss_wrapper::data_response); data.set_grant_meth(&iss_wrapper::data_grant); @@ -1354,6 +1358,8 @@ int iss_wrapper::build() new_slave_port("irq_req", &irq_req_itf); new_master_port("irq_ack", &irq_ack_itf); + new_master_port("busy", &busy_itf); + fetchen_itf.set_sync_meth(&iss_wrapper::fetchen_sync); new_slave_port("fetchen", &fetchen_itf); @@ -1439,7 +1445,8 @@ void iss_wrapper::start() INIT_LIST_HEAD(&this->trdb_packet_list); #endif - this->leakage_power.leakage_power_start(); + this->background_power.leakage_power_start(); + this->background_power.dynamic_power_start(); this->gdbserver = (vp::Gdbserver_engine *)this->get_service("gdbserver"); diff --git a/models/memory/memory_impl.cpp b/models/memory/memory_impl.cpp index 4f7b748..da3edb5 100644 --- a/models/memory/memory_impl.cpp +++ b/models/memory/memory_impl.cpp @@ -40,7 +40,6 @@ class memory : public vp::component private: - static void power_callback(void *__this, vp::clock_event *event); static void power_ctrl_sync(void *__this, bool value); vp::trace trace; @@ -60,14 +59,13 @@ class memory : public vp::component bool power_trigger; bool powered_up; - vp::power::power_source idle_power; vp::power::power_source read_8_power; vp::power::power_source read_16_power; vp::power::power_source read_32_power; vp::power::power_source write_8_power; vp::power::power_source write_16_power; vp::power::power_source write_32_power; - vp::power::power_source leakage_power; + vp::power::power_source background_power; vp::clock_event *power_event; int64_t last_access_timestamp; @@ -79,15 +77,6 @@ memory::memory(js::config *config) } -void memory::power_callback(void *__this, vp::clock_event *event) -{ - memory *_this = (memory *)__this; - if (_this->last_access_timestamp < _this->get_time()) - { - _this->idle_power.dynamic_power_start(); - } -} - vp::io_req_status_e memory::req(void *__this, vp::io_req *req) { memory *_this = (memory *)__this; @@ -142,9 +131,6 @@ vp::io_req_status_e memory::req(void *__this, vp::io_req *req) else if (size == 4) _this->read_32_power.account_energy_quantum(); } - - if (!_this->power_event->is_enqueued()) - _this->event_enqueue(_this->power_event, 1); } #ifdef VP_TRACE_ACTIVE @@ -223,8 +209,7 @@ int memory::build() js::config *config = get_js_config()->get("power_trigger"); this->power_trigger = config != NULL && config->get_bool(); - power.new_power_source("leakage", &leakage_power, this->get_js_config()->get("**/leakage")); - power.new_power_source("idle", &idle_power, this->get_js_config()->get("**/idle")); + power.new_power_source("leakage", &background_power, this->get_js_config()->get("**/background")); power.new_power_source("read_8", &read_8_power, this->get_js_config()->get("**/read_8")); power.new_power_source("read_16", &read_16_power, this->get_js_config()->get("**/read_16")); power.new_power_source("read_32", &read_32_power, this->get_js_config()->get("**/read_32")); @@ -232,8 +217,6 @@ int memory::build() power.new_power_source("write_16", &write_16_power, this->get_js_config()->get("**/write_16")); power.new_power_source("write_32", &write_32_power, this->get_js_config()->get("**/write_32")); - power_event = this->event_new(memory::power_callback); - return 0; } @@ -287,8 +270,8 @@ void memory::start() } } - this->leakage_power.leakage_power_start(); - this->idle_power.dynamic_power_start(); + this->background_power.leakage_power_start(); + this->background_power.dynamic_power_start(); this->last_access_timestamp = -1; } diff --git a/models/utils/composite_impl.cpp b/models/utils/composite_impl.cpp index 907075e..d5cf338 100644 --- a/models/utils/composite_impl.cpp +++ b/models/utils/composite_impl.cpp @@ -37,6 +37,7 @@ class composite : public vp::component int build(); void start(); + void power_supply_set(int state); void dump_traces(FILE *file); @@ -83,6 +84,10 @@ void composite::add_port(std::string name, vp::port *port) this->ports[name] = port; } +void composite::power_supply_set(int state) +{ + //printf("%s power set %d\n", this->get_path().c_str(), state); +} extern "C" vp::component *vp_constructor(js::config *config)