| /* Copyright (c) 2012 Massachusetts Institute of Technology |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a copy |
| * of this software and associated documentation files (the "Software"), to deal |
| * in the Software without restriction, including without limitation the rights |
| * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| * copies of the Software, and to permit persons to whom the Software is |
| * furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be included in |
| * all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| * THE SOFTWARE. |
| */ |
| |
| #include "model/ElectricalModel.h" |
| |
| #include "model/PortInfo.h" |
| #include "model/EventInfo.h" |
| #include "model/timing_graph/ElectricalDriver.h" |
| #include "model/timing_graph/ElectricalDriverMultiplier.h" |
| #include "model/timing_graph/ElectricalNet.h" |
| #include "model/timing_graph/ElectricalLoad.h" |
| #include "model/timing_graph/ElectricalDelay.h" |
| |
| namespace DSENT |
| { |
| ElectricalModel::ElectricalModel(const String& instance_name_, const TechModel* tech_model_) |
| : Model(instance_name_, tech_model_) |
| { |
| m_curr_driving_strengths_idx_ = -1; |
| m_input_ports_ = new Map<PortInfo*>; |
| m_output_ports_ = new Map<PortInfo*>; |
| m_net_references_ = new Map<NetIndex>; |
| m_drivers_ = new Map<ElectricalDriver*>; |
| m_driver_multipliers_ = new Map<ElectricalDriverMultiplier*>; |
| m_nets_ = new Map<ElectricalNet*>; |
| m_loads_ = new Map<ElectricalLoad*>; |
| m_delays_ = new Map<ElectricalDelay*>; |
| m_event_infos_ = new Map<EventInfo*>; |
| } |
| |
| ElectricalModel::~ElectricalModel() |
| { |
| deletePtrMap<PortInfo>(m_input_ports_); |
| deletePtrMap<PortInfo>(m_output_ports_); |
| delete m_net_references_; |
| deletePtrMap<ElectricalDriver>(m_drivers_); |
| deletePtrMap<ElectricalDriverMultiplier>(m_driver_multipliers_); |
| deletePtrMap<ElectricalNet>(m_nets_); |
| deletePtrMap<ElectricalLoad>(m_loads_); |
| deletePtrMap<ElectricalDelay>(m_delays_); |
| deletePtrMap<EventInfo>(m_event_infos_); |
| m_input_ports_ = NULL; |
| m_output_ports_ = NULL; |
| m_net_references_ = NULL; |
| m_drivers_ = NULL; |
| m_driver_multipliers_ = NULL; |
| m_nets_ = NULL; |
| m_loads_ = NULL; |
| m_net_references_ = NULL; |
| m_event_infos_ = NULL; |
| } |
| |
| void ElectricalModel::checkProperties() const |
| { |
| // Check if the specified driving strength exists in the available driving strengths |
| if(getProperties()->keyExist("DrivingStrength")) |
| { |
| const double driving_strength = getProperty("DrivingStrength"); |
| bool is_found = false; |
| for(int i = 0; i < (int)m_driving_strengths_.size(); ++i) |
| { |
| if(driving_strength == m_driving_strengths_[i]) |
| { |
| is_found = true; |
| break; |
| } |
| } |
| ASSERT(is_found, "[Error] " + getInstanceName() + |
| " -> Driving strength (" + String(driving_strength) + ")" |
| " not found in available driving strengths (" + |
| getParameter("AvailableDrivingStrengths")); |
| } |
| |
| // Do normal check on the properties |
| Model::checkProperties(); |
| return; |
| } |
| |
| double ElectricalModel::getDrivingStrength() const |
| { |
| if(m_curr_driving_strengths_idx_ == -1) |
| { |
| return 0; |
| } |
| else |
| { |
| return m_driving_strengths_[m_curr_driving_strengths_idx_]; |
| } |
| } |
| |
| int ElectricalModel::getDrivingStrengthIdx() const |
| { |
| return m_curr_driving_strengths_idx_; |
| } |
| |
| void ElectricalModel::setDrivingStrengthIdx(int idx_) |
| { |
| ASSERT(((idx_ >= 0) && (idx_ < (int)m_driving_strengths_.size())), |
| "[Error] " + getInstanceName() + |
| " -> Driving strength index out of range (" + String(idx_) + ")"); |
| |
| m_curr_driving_strengths_idx_ = idx_; |
| setProperty("DrivingStrength", m_driving_strengths_[m_curr_driving_strengths_idx_]); |
| |
| Log::printLine(getInstanceName() + " -> Changing drive strength to " + (String) m_driving_strengths_[m_curr_driving_strengths_idx_]); |
| update(); |
| return; |
| } |
| |
| void ElectricalModel::setMinDrivingStrength() |
| { |
| setDrivingStrengthIdx(0); |
| return; |
| } |
| |
| bool ElectricalModel::hasMinDrivingStrength() const |
| { |
| return (m_curr_driving_strengths_idx_ == 0); |
| } |
| |
| bool ElectricalModel::hasMaxDrivingStrength() const |
| { |
| return (m_curr_driving_strengths_idx_ == ((int)m_driving_strengths_.size() - 1)); |
| } |
| |
| void ElectricalModel::increaseDrivingStrength() |
| { |
| if(!hasMaxDrivingStrength()) |
| { |
| setDrivingStrengthIdx(m_curr_driving_strengths_idx_ + 1); |
| } |
| return; |
| } |
| |
| void ElectricalModel::decreaseDrivingStrength() |
| { |
| if(!hasMinDrivingStrength()) |
| { |
| setDrivingStrengthIdx(m_curr_driving_strengths_idx_ - 1); |
| } |
| return; |
| } |
| |
| void ElectricalModel::setAvailableDrivingStrengths(const String& driving_strengths_) |
| { |
| setParameter("AvailableDrivingStrengths", driving_strengths_); |
| const vector<String>& split_str = driving_strengths_.split("[,"); |
| |
| // Check if there is at least one driving strength specified |
| ASSERT(!split_str.empty(), "[Error] " + getInstanceName() + |
| " -> Specified driving strength string does not contain any driving strengths (" + |
| driving_strengths_ + ")"); |
| |
| // TODO - check if the driving strengths is sorted |
| |
| // Overwrite the available driving strengths |
| m_driving_strengths_.clear(); |
| for(int i = 0; i < (int)split_str.size(); ++i) |
| { |
| m_driving_strengths_.push_back(split_str[i].toDouble()); |
| } |
| |
| // Set the driving strength to minimum |
| m_curr_driving_strengths_idx_ = 0; |
| setProperty("DrivingStrength", m_driving_strengths_[m_curr_driving_strengths_idx_]); |
| return; |
| } |
| |
| // Connect a port (input or output) to some ElectricalNet |
| void ElectricalModel::portConnect(ElectricalModel* connect_model_, const String& connect_port_name_, const String& connect_net_name_) |
| { |
| ASSERT(m_net_references_->keyExist(connect_net_name_), "[Error] " + getInstanceName() + |
| " -> Net '" + connect_net_name_ + "' does not exist!"); |
| |
| portConnect(connect_model_, connect_port_name_, connect_net_name_, m_net_references_->get(connect_net_name_)); |
| } |
| |
| void ElectricalModel::portConnect(ElectricalModel* connect_model_, const String& connect_port_name_, const String& connect_net_name_, const NetIndex& connect_net_indices_) |
| { |
| ASSERT(m_net_references_->keyExist(connect_net_name_), "[Error] " + getInstanceName() + |
| " -> Net '" + connect_net_name_ + "' does not exist!"); |
| |
| // Check whether the port name is an input or output, ASSERTion error if neither |
| bool is_input = connect_model_->getInputs()->keyExist(connect_port_name_); |
| bool is_output = connect_model_->getOutputs()->keyExist(connect_port_name_); |
| |
| ASSERT(is_input || is_output, "[Error] " + getInstanceName() + " -> Model '" + connect_model_->getInstanceName() + |
| "' does not have a port named '" + connect_port_name_ + "'!"); |
| |
| int connect_net_width = connect_net_indices_.second - connect_net_indices_.first + 1; |
| const NetIndex& port_indices = connect_model_->getNetReference(connect_port_name_); |
| int port_width = port_indices.second - port_indices.first + 1; |
| |
| ASSERT(connect_net_width == port_width, "[Error] " + getInstanceName() + " -> Port width mismatch for Model '" + |
| connect_model_->getInstanceName() + "." + connect_port_name_ + toString(port_indices) + |
| "' and net '" + connect_net_name_ + toString(connect_net_indices_) + "'!"); |
| |
| int port_index = port_indices.first; |
| int connect_net_index = connect_net_indices_.first; |
| |
| if(is_input) |
| { |
| while(port_index <= port_indices.second) |
| { |
| getNet(connect_net_name_, makeNetIndex(connect_net_index))->addDownstreamNode( |
| connect_model_->getNet(connect_port_name_, makeNetIndex(port_index))); |
| ++port_index; |
| ++connect_net_index; |
| } |
| } |
| else if(is_output) |
| { |
| while (port_index <= port_indices.second) |
| { |
| connect_model_->getNet(connect_port_name_, makeNetIndex(port_index))->addDownstreamNode( |
| getNet(connect_net_name_, makeNetIndex(connect_net_index))); |
| ++port_index; |
| ++connect_net_index; |
| } |
| } |
| } |
| |
| //Get Drivers |
| const Map<ElectricalDriver*>* ElectricalModel::getDrivers() const |
| { |
| return m_drivers_; |
| } |
| |
| ElectricalDriver* ElectricalModel::getDriver(const String& name_) |
| { |
| return m_drivers_->get(name_); |
| } |
| |
| //Get Driver Multipliers |
| const Map<ElectricalDriverMultiplier*>* ElectricalModel::getDriverMultipliers() const |
| { |
| return m_driver_multipliers_; |
| } |
| |
| ElectricalDriverMultiplier* ElectricalModel::getDriverMultiplier(const String& name_) |
| { |
| return m_driver_multipliers_->get(name_); |
| } |
| |
| //Get Nets |
| const Map<ElectricalNet*>* ElectricalModel::getNets() const |
| { |
| return m_nets_; |
| } |
| |
| ElectricalNet* ElectricalModel::getNet(const String& name_) |
| { |
| return getNet(name_, m_net_references_->get(name_)); |
| } |
| |
| ElectricalNet* ElectricalModel::getNet(const String& name_, const NetIndex& index_) |
| { |
| ASSERT(index_.first == index_.second, "[Error] " + getInstanceName() + |
| " -> Ambiguous get net since (" + name_ + ") is a bus consisting of several nets!"); |
| return m_nets_->get(name_ + "[" + (String) index_.first + "]"); |
| } |
| |
| //Get Loads |
| const Map<ElectricalLoad*>* ElectricalModel::getLoads() const |
| { |
| return m_loads_; |
| } |
| |
| ElectricalLoad* ElectricalModel::getLoad(const String& name_) |
| { |
| return m_loads_->get(name_); |
| } |
| |
| //Get Delays |
| const Map<ElectricalDelay*>* ElectricalModel::getDelays() const |
| { |
| return m_delays_; |
| } |
| |
| ElectricalDelay* ElectricalModel::getDelay(const String& name_) |
| { |
| return m_delays_->get(name_); |
| } |
| |
| //Get Inputs |
| const Map<PortInfo*>* ElectricalModel::getInputs() const |
| { |
| return m_input_ports_; |
| } |
| |
| PortInfo* ElectricalModel::getInputPort(const String& name_) |
| { |
| ASSERT(m_input_ports_->keyExist(name_), "[Error] " + getInstanceName() + |
| " -> Input port (" + name_ + ") does not exist"); |
| |
| return m_input_ports_->get(name_); |
| } |
| |
| const PortInfo* ElectricalModel::getInputPort(const String& name_) const |
| { |
| ASSERT(m_input_ports_->keyExist(name_), "[Error] " + getInstanceName() + |
| " -> Input port (" + name_ + ") does not exist"); |
| |
| return m_input_ports_->get(name_); |
| } |
| |
| //Get Outputs |
| const Map<PortInfo*>* ElectricalModel::getOutputs() const |
| { |
| return m_output_ports_; |
| } |
| |
| PortInfo* ElectricalModel::getOutputPort(const String& name_) |
| { |
| ASSERT(m_output_ports_->keyExist(name_), "[Error] " + getInstanceName() + |
| " -> Output port (" + name_ + ") does not exist"); |
| |
| return m_output_ports_->get(name_); |
| } |
| |
| const PortInfo* ElectricalModel::getOutputPort(const String& name_) const |
| { |
| ASSERT(m_output_ports_->keyExist(name_), "[Error] " + getInstanceName() + |
| " -> Output port (" + name_ + ") does not exist"); |
| |
| return m_output_ports_->get(name_); |
| } |
| |
| const Map<NetIndex>* ElectricalModel::getNetReferences() const |
| { |
| return m_net_references_; |
| } |
| |
| const NetIndex ElectricalModel::getNetReference(const String& name_) const |
| { |
| return m_net_references_->get(name_); |
| } |
| |
| //------------------------------------------------------------------------- |
| // Electrical Connectivity and Timing Element Creation Functions |
| //------------------------------------------------------------------------- |
| |
| // Input Port creation |
| void ElectricalModel::createInputPort(const String& name_, const NetIndex& net_indices_) |
| { |
| // Create the new nets (including its net reference) |
| // This should already check that it has not been previously declared |
| createNet(name_, net_indices_); |
| // Add the net name to list of input ports |
| m_input_ports_->set(name_, new PortInfo(name_, net_indices_)); |
| return; |
| } |
| |
| // Output Port creation |
| void ElectricalModel::createOutputPort(const String& name_, const NetIndex& net_indices_) |
| { |
| // Create the new nets (including its net reference) |
| // This should already check that it has not been previously declared |
| createNet(name_, net_indices_); |
| // Add the net name to list of output ports |
| m_output_ports_->set(name_, new PortInfo(name_, net_indices_)); |
| return; |
| } |
| |
| // Net creation |
| void ElectricalModel::createNet(const String& name_) |
| { |
| // Creating a net with specifying an index range means that the net is just |
| // a 1-bit wire indexed at [0] |
| createNet(name_, makeNetIndex(0, 0)); |
| return; |
| } |
| |
| void ElectricalModel::createNet(const String& name_, const NetIndex& net_indices_) |
| { |
| // Check that it hasn't been previously declared |
| ASSERT( !m_nets_->keyExist(name_) && !m_net_references_->keyExist(name_), |
| "[Error] " + getInstanceName() + " -> Redeclaration of net " + name_); |
| |
| int start = net_indices_.first; |
| int end = net_indices_.second; |
| |
| for (int index = start; index <= end; ++index) |
| { |
| String indexed_name = name_ + "[" + (String) index + "]"; |
| // Create the new net |
| ElectricalNet* net = new ElectricalNet(indexed_name, this); |
| // Add the net to net map |
| m_nets_->set(indexed_name, net); |
| } |
| // Add net to net references |
| m_net_references_->set(name_, net_indices_); |
| return; |
| } |
| |
| // Driver creation |
| void ElectricalModel::createDriver(const String& name_, bool sizable_) |
| { |
| // Check that it hasn't been previously declared |
| ASSERT( !m_drivers_->keyExist(name_), |
| "[Error] " + getInstanceName() + " -> Redeclaration of driver " + name_); |
| |
| ElectricalDriver* driver = new ElectricalDriver(name_, this, sizable_); |
| m_drivers_->set(name_, driver); |
| return; |
| } |
| |
| /* |
| void ElectricalModel::createDriver(const String& name_, bool sizable_, int start_index_, int end_index_) |
| { |
| for (int index = start_index_; index <= end_index_; ++index) |
| { |
| createDriver(name_ + "[" + (String) index + "]", sizable_); |
| } |
| return; |
| } |
| */ |
| |
| // Driver Multiplier creation |
| void ElectricalModel::createDriverMultiplier(const String& name_) |
| { |
| // Check that it hasn't been previously declared |
| ASSERT( !m_driver_multipliers_->keyExist(name_), |
| "[Error] " + getInstanceName() + " -> Redeclaration of driver_multiplier " + name_); |
| |
| ElectricalDriverMultiplier* driver_multiplier = new ElectricalDriverMultiplier(name_, this); |
| m_driver_multipliers_->set(name_, driver_multiplier); |
| return; |
| } |
| |
| // Load creation |
| |
| void ElectricalModel::createLoad(const String& name_) |
| { |
| // Check that it hasn't been previously declared |
| ASSERT( !m_loads_->keyExist(name_), |
| "[Error] " + getInstanceName() + " -> Redeclaration of load " + name_); |
| |
| ElectricalLoad* load = new ElectricalLoad(name_, this); |
| m_loads_->set(name_, load); |
| return; |
| } |
| |
| /* |
| void ElectricalModel::createLoad(const String& name_, int start_index_, int end_index_) |
| { |
| for (int index = start_index_; index <= end_index_; ++index) |
| { |
| createLoad(name_ + "[" + (String) index + "]"); |
| } |
| return; |
| } |
| */ |
| |
| // Delay creation |
| void ElectricalModel::createDelay(const String& name_) |
| { |
| // Check that it hasn't been previously declared |
| ASSERT( !m_delays_->keyExist(name_), |
| "[Error] " + getInstanceName() + " -> Redeclaration of delay " + name_); |
| |
| ElectricalDelay* delay = new ElectricalDelay(name_, this); |
| m_delays_->set(name_, delay); |
| return; |
| } |
| |
| /* |
| void ElectricalModel::createDelay(const String& name_, int start_index_, int end_index_) |
| { |
| for (int index = start_index_; index <= end_index_; ++index) |
| { |
| createDelay(name_ + "[" + (String) index + "]"); |
| } |
| return; |
| } |
| */ |
| //------------------------------------------------------------------------- |
| |
| // Assign a net to be downstream from another net |
| // case 1: 'assign downstream_net_name_ = upstream_net_name_' |
| void ElectricalModel::assign(const String& downstream_net_name_, const String& upstream_net_name_) |
| { |
| ASSERT(getNetReferences()->keyExist(downstream_net_name_), "[Error] " + getInstanceName() + " -> Net '" + |
| downstream_net_name_ + "' does not exist!"); |
| |
| ASSERT(getNetReferences()->keyExist(upstream_net_name_), "[Error] " + getInstanceName() + " -> Net '" + |
| upstream_net_name_ + "' does not exist!"); |
| |
| assign(downstream_net_name_, getNetReference(downstream_net_name_), |
| upstream_net_name_, getNetReference(upstream_net_name_)); |
| |
| return; |
| } |
| |
| // case 2: 'assign downstream_net_name_[begin:end] = upstream_net_name_' |
| void ElectricalModel::assign(const String& downstream_net_name_, const NetIndex& downstream_net_indices_, const String& upstream_net_name_) |
| { |
| ASSERT(getNetReferences()->keyExist(downstream_net_name_), "[Error] " + getInstanceName() + " -> Net '" + |
| downstream_net_name_ + "' does not exist!"); |
| |
| ASSERT(getNetReferences()->keyExist(upstream_net_name_), "[Error] " + getInstanceName() + " -> Net '" + |
| upstream_net_name_ + "' does not exist!"); |
| |
| assign(downstream_net_name_, downstream_net_indices_, |
| upstream_net_name_, getNetReference(upstream_net_name_)); |
| |
| return; |
| } |
| |
| // case 3: 'assign downstream_net_name_ = upstream_net_name_[begin:end]' |
| void ElectricalModel::assign(const String& downstream_net_name_, const String& upstream_net_name_, const NetIndex& upstream_net_indices_) |
| { |
| ASSERT(getNetReferences()->keyExist(downstream_net_name_), "[Error] " + getInstanceName() + " -> Net '" + |
| downstream_net_name_ + "' does not exist!"); |
| |
| ASSERT(getNetReferences()->keyExist(upstream_net_name_), "[Error] " + getInstanceName() + " -> Net '" + |
| upstream_net_name_ + "' does not exist!"); |
| |
| assign(downstream_net_name_, getNetReference(downstream_net_name_), |
| upstream_net_name_, upstream_net_indices_); |
| |
| return; |
| } |
| // case 4: 'assign downstream_net_name_[begin:end] = upstream_net_name_[begin:end]' |
| void ElectricalModel::assign(const String& downstream_net_name_, const NetIndex& downstream_net_indices_, const String& upstream_net_name_, const NetIndex& upstream_net_indices_) |
| { |
| ASSERT(getNetReferences()->keyExist(downstream_net_name_), "[Error] " + getInstanceName() + " -> Net '" + |
| downstream_net_name_ + "' does not exist!"); |
| |
| ASSERT(getNetReferences()->keyExist(upstream_net_name_), "[Error] " + getInstanceName() + " -> Net '" + |
| upstream_net_name_ + "' does not exist!"); |
| |
| // Check that the assignment widths are the same |
| int downstream_width = downstream_net_indices_.second - downstream_net_indices_.first + 1; |
| int upstream_width = upstream_net_indices_.second - upstream_net_indices_.first + 1; |
| |
| ASSERT(downstream_width == upstream_width, "[Error] " + getInstanceName() + " -> Assignment width mismatch: " + |
| downstream_net_name_ + " (" + (String) downstream_width + ") and " + |
| upstream_net_name_ + " (" + (String) upstream_width + ")"); |
| |
| // Loop through indices and connect them together |
| int down_index = downstream_net_indices_.first; |
| int up_index = upstream_net_indices_.first; |
| while (down_index <= downstream_net_indices_.second) |
| { |
| getNet(upstream_net_name_, makeNetIndex(up_index))->addDownstreamNode( |
| getNet(downstream_net_name_, makeNetIndex(down_index))); |
| |
| ++up_index; |
| ++down_index; |
| } |
| |
| return; |
| } |
| |
| // Assign a net to another net through a driver multiplier |
| void ElectricalModel::assignVirtualFanout(const String& downstream_net_name_, const String& upstream_net_name_) |
| { |
| ASSERT(getNetReferences()->keyExist(upstream_net_name_), "[Error] " + getInstanceName() + |
| " -> Net '" + upstream_net_name_ + "' does not exist!"); |
| ASSERT(getNetReferences()->keyExist(downstream_net_name_), "[Error] " + getInstanceName() + |
| " -> Net '" + downstream_net_name_ + "' does not exist!"); |
| |
| assignVirtualFanout(downstream_net_name_, getNetReference(downstream_net_name_), upstream_net_name_, getNetReference(upstream_net_name_)); |
| return; |
| } |
| |
| // Assign a net to another net through a driver multiplier |
| void ElectricalModel::assignVirtualFanout(const String& downstream_net_name_, const NetIndex& downstream_net_indices_, const String& upstream_net_name_, const NetIndex& upstream_net_indices_) |
| { |
| ASSERT(getNetReferences()->keyExist(upstream_net_name_), "[Error] " + getInstanceName() + |
| " -> Net '" + upstream_net_name_ + "' does not exist!"); |
| ASSERT(getNetReferences()->keyExist(downstream_net_name_), "[Error] " + getInstanceName() + |
| " -> Net '" + downstream_net_name_ + "' does not exist!"); |
| |
| const String& drive_mult_name = upstream_net_name_ + "_" + (String) upstream_net_indices_.first + "_DriverMultiplier"; |
| bool is_drive_mult_exist = getDriverMultipliers()->keyExist(drive_mult_name); |
| |
| // Create a driver multiplier and assign it to upstream_net since it doesn't exist |
| if(!is_drive_mult_exist) |
| { |
| createDriverMultiplier(drive_mult_name); |
| getNet(upstream_net_name_, upstream_net_indices_)->addDownstreamNode(getDriverMultiplier(drive_mult_name)); |
| } |
| |
| // Assign downstream_net_name_[end:begin] = driver_multiplier_name_ |
| ElectricalDriverMultiplier* drive_mult = getDriverMultiplier(drive_mult_name); |
| int begin_index = downstream_net_indices_.first; |
| int end_index = downstream_net_indices_.second; |
| for(int i = begin_index; i <= end_index; ++i) |
| { |
| drive_mult->addDownstreamNode(getNet(downstream_net_name_, makeNetIndex(i))); |
| } |
| return; |
| } |
| |
| void ElectricalModel::assignVirtualFanin(const String& downstream_net_name_, const String& upstream_net_name_) |
| { |
| ASSERT(getNetReferences()->keyExist(upstream_net_name_), "[Error] " + getInstanceName() + |
| " -> Net '" + upstream_net_name_ + "' does not exist!"); |
| ASSERT(getNetReferences()->keyExist(downstream_net_name_), "[Error] " + getInstanceName() + |
| " -> Net '" + downstream_net_name_ + "' does not exist!"); |
| |
| assignVirtualFanin(downstream_net_name_, getNetReference(downstream_net_name_), upstream_net_name_, getNetReference(upstream_net_name_)); |
| return; |
| } |
| |
| void ElectricalModel::assignVirtualFanin(const String& downstream_net_name_, const NetIndex& downstream_net_indices_, const String& upstream_net_name_, const NetIndex& upstream_net_indices_) |
| { |
| ASSERT(getNetReferences()->keyExist(upstream_net_name_), "[Error] " + getInstanceName() + |
| " -> Net '" + upstream_net_name_ + "' does not exist!"); |
| ASSERT(getNetReferences()->keyExist(downstream_net_name_), "[Error] " + getInstanceName() + |
| " -> Net '" + downstream_net_name_ + "' does not exist!"); |
| |
| int begin_index = upstream_net_indices_.first; |
| int end_index = upstream_net_indices_.second; |
| |
| for(int i = begin_index; i <= end_index; ++i) |
| { |
| getNet(upstream_net_name_, makeNetIndex(i))->addDownstreamNode(getNet(downstream_net_name_, downstream_net_indices_)); |
| } |
| return; |
| } |
| |
| void ElectricalModel::createElectricalResults() |
| { |
| // Add active area result |
| addAreaResult(new Result("Active")); |
| |
| // Add wire area result |
| TechModel::ConstWireLayerIterator it_begin = getTechModel()->getAvailableWireLayers()->begin(); |
| TechModel::ConstWireLayerIterator it_end = getTechModel()->getAvailableWireLayers()->end(); |
| TechModel::ConstWireLayerIterator it; |
| for(it = it_begin; it != it_end; ++it) |
| { |
| const String& layer_name = (*it); |
| addAreaResult(new Result(layer_name + "Wire")); |
| } |
| |
| // Add leakage result |
| addNddPowerResult(new Result("Leakage")); |
| |
| // Add idle event result |
| createElectricalEventResult("Idle"); |
| return; |
| } |
| |
| void ElectricalModel::addElectricalSubResults(const ElectricalModel* model_, double number_models_) |
| { |
| // Add active area sub result |
| getAreaResult("Active")->addSubResult(model_->getAreaResult("Active"), model_->getInstanceName(), number_models_); |
| |
| // Add wire area sub result |
| TechModel::ConstWireLayerIterator it_begin = getTechModel()->getAvailableWireLayers()->begin(); |
| TechModel::ConstWireLayerIterator it_end = getTechModel()->getAvailableWireLayers()->end(); |
| TechModel::ConstWireLayerIterator it; |
| for(it = it_begin; it != it_end; ++it) |
| { |
| const String& layer_name = (*it); |
| const String& result_name = layer_name + "Wire"; |
| getAreaResult(result_name)->addSubResult(model_->getAreaResult(result_name), model_->getInstanceName(), number_models_); |
| } |
| |
| // Add leakage sub result |
| getNddPowerResult("Leakage")->addSubResult(model_->getNddPowerResult("Leakage"), model_->getInstanceName(), number_models_); |
| |
| // Add idle event sub result |
| getEventResult("Idle")->addSubResult(model_->getEventResult("Idle"), model_->getInstanceName(), number_models_); |
| return; |
| } |
| |
| void ElectricalModel::addElectricalWireSubResult(const String& wire_layer_, const Result* result_, const String& producer_, double number_results_) |
| { |
| getAreaResult(wire_layer_ + "Wire")->addSubResult(result_, producer_, number_results_); |
| return; |
| } |
| |
| void ElectricalModel::createElectricalAtomicResults() |
| { |
| // Add active area result |
| addAreaResult(new AtomicResult("Active")); |
| |
| // Add wire area result |
| TechModel::ConstWireLayerIterator it_begin = getTechModel()->getAvailableWireLayers()->begin(); |
| TechModel::ConstWireLayerIterator it_end = getTechModel()->getAvailableWireLayers()->end(); |
| TechModel::ConstWireLayerIterator it; |
| for(it = it_begin; it != it_end; ++it) |
| { |
| const String& layer_name = (*it); |
| addAreaResult(new AtomicResult(layer_name + "Wire")); |
| } |
| |
| // Add leakage result |
| addNddPowerResult(new AtomicResult("Leakage")); |
| |
| // Add idle event result |
| createElectricalEventAtomicResult("Idle"); |
| return; |
| } |
| |
| void ElectricalModel::addElecticalAtomicResultValues(const ElectricalModel* model_, double number_models_) |
| { |
| getAreaResult("Active")->addValue(model_->getAreaResult("Active")->calculateSum() * number_models_); |
| |
| // Add wire area sub result |
| TechModel::ConstWireLayerIterator it_begin = getTechModel()->getAvailableWireLayers()->begin(); |
| TechModel::ConstWireLayerIterator it_end = getTechModel()->getAvailableWireLayers()->end(); |
| TechModel::ConstWireLayerIterator it; |
| for(it = it_begin; it != it_end; ++it) |
| { |
| const String& layer_name = (*it); |
| const String& result_name = layer_name + "Wire"; |
| getAreaResult(result_name)->addValue(model_->getAreaResult(result_name)->calculateSum() * number_models_); |
| } |
| |
| // Add leakage sub result |
| getNddPowerResult("Leakage")->addValue(model_->getNddPowerResult("Leakage")->calculateSum() * number_models_); |
| |
| // Add idle event sub result |
| getEventResult("Idle")->addValue(model_->getEventResult("Idle")->calculateSum() * number_models_); |
| return; |
| } |
| |
| void ElectricalModel::addElecticalWireAtomicResultValue(const String& wire_layer_, double value_) |
| { |
| getAreaResult(wire_layer_ + "Wire")->addValue(value_); |
| return; |
| } |
| |
| void ElectricalModel::resetElectricalAtomicResults() |
| { |
| getAreaResult("Active")->setValue(0.0); |
| |
| // Reset wire area sub result |
| TechModel::ConstWireLayerIterator it_begin = getTechModel()->getAvailableWireLayers()->begin(); |
| TechModel::ConstWireLayerIterator it_end = getTechModel()->getAvailableWireLayers()->end(); |
| TechModel::ConstWireLayerIterator it; |
| for(it = it_begin; it != it_end; ++it) |
| { |
| const String& layer_name = (*it); |
| const String& result_name = layer_name + "Wire"; |
| getAreaResult(result_name)->setValue(0.0); |
| } |
| |
| // Reset leakage sub result |
| getNddPowerResult("Leakage")->setValue(0.0); |
| |
| // Reset idle event sub result |
| getEventResult("Idle")->setValue(0.0); |
| |
| return; |
| } |
| |
| void ElectricalModel::createElectricalEventResult(const String& name_) |
| { |
| // Add the event result |
| addEventResult(new Result(name_)); |
| // Add event info |
| m_event_infos_->set(name_, new EventInfo(name_, getInputs())); |
| return; |
| } |
| |
| void ElectricalModel::createElectricalEventAtomicResult(const String& name_) |
| { |
| // Add the event result |
| addEventResult(new AtomicResult(name_)); |
| // Add event info |
| m_event_infos_->set(name_, new EventInfo(name_, getInputs())); |
| return; |
| } |
| |
| void ElectricalModel::assignPortTransitionInfo(ElectricalModel* downstream_model_, const String& downstream_port_name_, const TransitionInfo& trans_info_) |
| { |
| ASSERT(downstream_model_ != NULL, "[Error] " + getInstanceName() + |
| " -> Downstream model does not exist"); |
| |
| downstream_model_->getInputPort(downstream_port_name_)->setTransitionInfo(trans_info_); |
| return; |
| } |
| |
| void ElectricalModel::propagatePortTransitionInfo(const String& downstream_port_name_, const String& upstream_port_name_) |
| { |
| const TransitionInfo& trans_info = getInputPort(upstream_port_name_)->getTransitionInfo(); |
| getOutputPort(downstream_port_name_)->setTransitionInfo(trans_info); |
| return; |
| } |
| |
| void ElectricalModel::propagatePortTransitionInfo(ElectricalModel* downstream_model_, const String& downstream_port_name_, const String& upstream_port_name_) |
| { |
| ASSERT(downstream_model_ != NULL, "[Error] " + getInstanceName() + |
| " -> Downstream model does not exist"); |
| |
| const TransitionInfo& trans_info = getInputPort(upstream_port_name_)->getTransitionInfo(); |
| downstream_model_->getInputPort(downstream_port_name_)->setTransitionInfo(trans_info); |
| return; |
| } |
| |
| void ElectricalModel::propagatePortTransitionInfo(ElectricalModel* downstream_model_, const String& downstream_port_name_, const ElectricalModel* upstream_model_, const String& upstream_port_name_) |
| { |
| ASSERT(downstream_model_ != NULL, "[Error] " + getInstanceName() + |
| " -> Downstream model does not exist"); |
| ASSERT(upstream_model_ != NULL, "[Error] " + getInstanceName() + |
| " -> Upstream model does not exist"); |
| |
| const TransitionInfo& trans_info = upstream_model_->getOutputPort(upstream_port_name_)->getTransitionInfo(); |
| |
| downstream_model_->getInputPort(downstream_port_name_)->setTransitionInfo(trans_info); |
| return; |
| } |
| |
| void ElectricalModel::propagatePortTransitionInfo(const String& downstream_port_name_, const ElectricalModel* upstream_model_, const String& upstream_port_name_) |
| { |
| ASSERT(upstream_model_ != NULL, "[Error] " + getInstanceName() + |
| " -> Upstream model does not exist"); |
| |
| const TransitionInfo& trans_info = upstream_model_->getOutputPort(upstream_port_name_)->getTransitionInfo(); |
| getOutputPort(downstream_port_name_)->setTransitionInfo(trans_info); |
| return; |
| } |
| |
| void ElectricalModel::propagateTransitionInfo() |
| { |
| // by default do nothing. |
| } |
| |
| void ElectricalModel::useModel(const String& event_name_) |
| { |
| getGenProperties()->set("UseModelEvent", event_name_); |
| applyTransitionInfo(event_name_); |
| useModel(); |
| return; |
| } |
| |
| void ElectricalModel::useModel() |
| { |
| propagateTransitionInfo(); |
| return; |
| } |
| |
| void ElectricalModel::applyTransitionInfo(const String& event_name_) |
| { |
| // Check if the event actually exists |
| ASSERT(hasEventResult(event_name_), "[Error] " + getInstanceName() + |
| " -> Event (" + event_name_ + ") does not exist in the result map"); |
| ASSERT(m_event_infos_->keyExist(event_name_), "[Error] " + getInstanceName() + |
| " -> Event (" + event_name_ + ") does not exist in the event info map"); |
| |
| const EventInfo* event_info = m_event_infos_->get(event_name_); |
| |
| // Set the input ports' transition information for the event |
| Map<PortInfo*>::ConstIterator it_begin = m_input_ports_->begin(); |
| Map<PortInfo*>::ConstIterator it_end = m_input_ports_->end(); |
| Map<PortInfo*>::ConstIterator it; |
| for(it = it_begin; it != it_end; ++it) |
| { |
| const String& port_name = it->first; |
| PortInfo* port_info = it->second; |
| const TransitionInfo& trans_info = event_info->getTransitionInfo(port_name); |
| port_info->setTransitionInfo(trans_info); |
| } |
| |
| return; |
| } |
| |
| EventInfo* ElectricalModel::getEventInfo(const String& event_name_) |
| { |
| ASSERT(m_event_infos_->keyExist(event_name_), "[Error] " + getInstanceName() + |
| " -> Event (" + event_name_ + ") does not exist"); |
| |
| return m_event_infos_->get(event_name_); |
| } |
| |
| } // namespace DSENT |
| |