diff options
author | Nilay Vaish <nilay@cs.wisc.edu> | 2014-10-11 15:02:23 -0500 |
---|---|---|
committer | Nilay Vaish <nilay@cs.wisc.edu> | 2014-10-11 15:02:23 -0500 |
commit | e8ed7b1d1b5bef31e9874f679a5797c2e00d06f1 (patch) | |
tree | 421c9c50377aa664958685914f5504c4c019e21f /ext/dsent/model | |
parent | a098fad174d8559037602b248b8e6f7f46bfebbb (diff) | |
download | gem5-e8ed7b1d1b5bef31e9874f679a5797c2e00d06f1.tar.xz |
ext: add the source code for DSENT
This patch adds a tool called DSENT to the ext/ directory. DSENT
is a tool that models power and area for on-chip networks. The next
patch adds a script for using the tool.
Diffstat (limited to 'ext/dsent/model')
138 files changed, 20585 insertions, 0 deletions
diff --git a/ext/dsent/model/ElectricalModel.cc b/ext/dsent/model/ElectricalModel.cc new file mode 100644 index 000000000..469e26c9e --- /dev/null +++ b/ext/dsent/model/ElectricalModel.cc @@ -0,0 +1,871 @@ +#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 + diff --git a/ext/dsent/model/ElectricalModel.h b/ext/dsent/model/ElectricalModel.h new file mode 100644 index 000000000..15dfefd78 --- /dev/null +++ b/ext/dsent/model/ElectricalModel.h @@ -0,0 +1,244 @@ +#ifndef __DSENT_MODEL_ELECTRICALMODEL_H__ +#define __DSENT_MODEL_ELECTRICALMODEL_H__ + +#include "util/CommonType.h" +#include "model/Model.h" +#include "model/TransitionInfo.h" + +namespace DSENT +{ + class PortInfo; + class EventInfo; + class ElectricalDriver; + class ElectricalDriverMultiplier; + class ElectricalNet; + class ElectricalLoad; + class ElectricalDelay; + + // A Net index consisting of a start and end index + typedef std::pair<int, int> NetIndex; + + // Helper function to make net index + inline NetIndex makeNetIndex(int start_index_, int end_index_) + { + ASSERT((end_index_ >= start_index_), (String)"[Error] Invalid net index range " + + + "[" + (String)start_index_ + ":" + (String)end_index_ + "]"); + + return NetIndex(start_index_, end_index_); + } + + // Helper function to make net index + inline NetIndex makeNetIndex(int index_) + { + return makeNetIndex(index_, index_); + } + + // Helper function to trun NetIndex to String + inline String toString(const NetIndex& net_index_) + { + return "[" + String(net_index_.second) + ":" + String(net_index_.first) + "]"; + } + + // ElectricalModel specifies physical connectivity to other models as well as the port + // parameters for the current model + class ElectricalModel : public Model + { + public: + ElectricalModel(const String& instance_name_, const TechModel* tech_model_); + virtual ~ElectricalModel(); + + public: + // Check if all properties needed exist in the m_properties_ + virtual void checkProperties() const; + // Set available driving strength vector from string + void setAvailableDrivingStrengths(const String& driving_strengths_); + + //----------------------------------------------------------------- + // Connectivity specification + //----------------------------------------------------------------- + // Net Indices + const Map<NetIndex>* getNetReferences() const; + const NetIndex getNetReference(const String& name_) const; + // Input Ports + void createInputPort(const String& name_, const NetIndex& net_indices_ = NetIndex(0, 0)); + const Map<PortInfo*>* getInputs() const; + PortInfo* getInputPort(const String& name_); + const PortInfo* getInputPort(const String& name_) const; + // Output Ports + void createOutputPort(const String& name_, const NetIndex& net_indices_ = NetIndex(0, 0)); + const Map<PortInfo*>* getOutputs() const; + PortInfo* getOutputPort(const String& name_); + const PortInfo* getOutputPort(const String& name_) const; + // Electrical Nets + void createNet(const String& name_); + void createNet(const String& name_, const NetIndex& net_indices_); + const Map<ElectricalNet*>* getNets() const; + ElectricalNet* getNet(const String& name_); + ElectricalNet* getNet(const String& name_, const NetIndex& index_); + + // Assign a net to be downstream from another net + // case 1: 'assign downstream_net_name_ = upstream_net_name_' + void assign(const String& downstream_net_name_, const String& upstream_net_name_); + // case 2: 'assign downstream_net_name_[end:begin] = upstream_net_name_' + void assign(const String& downstream_net_name_, const NetIndex& downstream_net_indices_, const String& upstream_net_name_); + // case 3: 'assign downstream_net_name_ = upstream_net_name_[end:begin]' + void assign(const String& downstream_net_name_, const String& upstream_net_name_, const NetIndex& upstream_net_indices_); + // case 4: 'assign downstream_net_name_[end:begin] = upstream_net_name_[end:begin]' + void assign(const String& downstream_net_name_, const NetIndex& downstream_net_indices_, const String& upstream_net_name_, const NetIndex& upstream_net_indices_); + + // Connect a port (input or output) to some ElectricalNet + // case 1: .connect_port_name_(connect_net_name_) + void portConnect(ElectricalModel* connect_model_, const String& connect_port_name_, const String& connect_net_name_); + // case 2: .connect_port_name_(connect_net_name[end:begin]) + void portConnect(ElectricalModel* connect_model_, const String& connect_port_name_, const String& connect_net_name_, const NetIndex& connect_net_indices_); + + // Assign a net to be downstream from another net through a driver multipliers + void assignVirtualFanout(const String& downstream_net_name_, const String& upstream_net_name_); + void assignVirtualFanout(const String& downstream_net_name_, const NetIndex& downstream_net_indices_, const String& upstream_net_name_, const NetIndex& upstream_net_indices_); + // Assign a net to be downstream from another net + // This is used to enable bit_duplication + void assignVirtualFanin(const String& downstream_net_name_, const String& upstream_net_name_); + void assignVirtualFanin(const String& downstream_net_name_, const NetIndex& downstream_net_indices_, const String& upstream_net_name_, const NetIndex& upstream_net_indices_); + //----------------------------------------------------------------- + + //----------------------------------------------------------------- + // Timing Model Components + //----------------------------------------------------------------- + // Electrical Drivers + void createDriver(const String& name_, bool sizable_); + //void createDriver(const String& name_, bool sizable_, int start_index_, int end_index_); + const Map<ElectricalDriver*>* getDrivers() const; + ElectricalDriver* getDriver(const String& name_); + // Electrical Driver Multipliers + void createDriverMultiplier(const String& name_); + const Map<ElectricalDriverMultiplier*>* getDriverMultipliers() const; + ElectricalDriverMultiplier* getDriverMultiplier(const String& name_); + + + // Electrical Loads + void createLoad(const String& name_); + //void createLoad(const String& name_, int start_index_, int end_index_); + const Map<ElectricalLoad*>* getLoads() const; + ElectricalLoad* getLoad(const String& name_); + // Electrical Delay creation + void createDelay(const String& name_); + //void createDelay(const String& name_, int start_index_, int end_index_); + const Map<ElectricalDelay*>* getDelays() const; + ElectricalDelay* getDelay(const String& name_); + //----------------------------------------------------------------- + + // Get current driving strength + double getDrivingStrength() const; + // Get current driving strength index + int getDrivingStrengthIdx() const; + // Set driving strength by index + void setDrivingStrengthIdx(int idx_); + // Set the instance to minimum driving strength + void setMinDrivingStrength(); + // Return true if the instance has minimum driving strength + bool hasMinDrivingStrength() const; + // Return true if the instance has maximum driving strength + bool hasMaxDrivingStrength() const; + // Increase driving strength index by 1 + void increaseDrivingStrength(); + // Decrease driving strength index by 1 + void decreaseDrivingStrength(); + + // Create the default sets of the electrical results + void createElectricalResults(); + // Add the default sets of the electrical results from a model + void addElectricalSubResults(const ElectricalModel* model_, double number_models_); + // Add extra wire sub results + void addElectricalWireSubResult(const String& wire_layer_, const Result* result_, const String& producer_, double number_results_); + // Create the default sets of the electrical atomic results + void createElectricalAtomicResults(); + // Accumulate the electrical atomic results' values + void addElecticalAtomicResultValues(const ElectricalModel* model_, double number_models_); + // Add extra wire sub results + void addElecticalWireAtomicResultValue(const String& wire_layer_, double value_); + // Reset the electrical atomic results' values + void resetElectricalAtomicResults(); + // Create an electrical event result. This will add an event associate to all input/output ports + void createElectricalEventResult(const String& name_); + // Create an electrical event atomic result + void createElectricalEventAtomicResult(const String& name_); + + //----------------------------------------------------------------- + // Helper functions to propagate transition information + //----------------------------------------------------------------- + void assignPortTransitionInfo(ElectricalModel* downstream_model_, const String& downstream_port_name_, const TransitionInfo& trans_info_); + void propagatePortTransitionInfo(const String& downstream_port_name_, const String& upstream_port_name_); + void propagatePortTransitionInfo(ElectricalModel* downstream_model_, const String& downstream_port_name_, const String& upstream_port_name_); + void propagatePortTransitionInfo(ElectricalModel* downstream_model_, const String& downstream_port_name_, const ElectricalModel* upstream_model_, const String& upstream_port_name_); + void propagatePortTransitionInfo(const String& downstream_port_name_, const ElectricalModel* upstream_model_, const String& upstream_port_name_); + virtual void propagateTransitionInfo(); + //----------------------------------------------------------------- + + //----------------------------------------------------------------- + // Helper functions to insert and remove buffers + //----------------------------------------------------------------- + + //----------------------------------------------------------------- + + virtual void useModel(const String& event_name_); + virtual void useModel(); + // TODO - add comments + void applyTransitionInfo(const String& event_name_); + // TODO - add comments + EventInfo* getEventInfo(const String& event_name_); + + protected: + // In an ElectricalModel, the complete port-to-port connectivity + // of all sub-instance must be specified. Addition/Removal ports or + // port-related nets cannot happen after this step + //virtual void constructModel() = 0; + // In an ElectricalModel, updateModel MUST finish all necessary + // calculations such that a timing model can be run + //virtual void updateModel() = 0; + // In an ElectricalModel, evaluateModel should calculate all + // event energies, now that the connectivity and timing has been + // completed + //virtual void evaluateModel() = 0; + + private: + // Private copy constructor. Use clone to perform copy operation. + ElectricalModel(const ElectricalModel& model_); + + private: + // Contains the driving strengths in increasing order + vector<double> m_driving_strengths_; + // Driving strength index in the driving strength vector + int m_curr_driving_strengths_idx_; + + //Connectivity elements + // Nets can come in various bus widths. A net reference is really + // just a helper map mapping a referenced map name to a bunch of + // net indices. A net index returns the starting and end indices of + // a net if the net is a multi-bit bus of some sort + Map<NetIndex>* m_net_references_; + // Map of the input ports + Map<PortInfo*>* m_input_ports_; + // Map of the output ports + Map<PortInfo*>* m_output_ports_; + // Map of all our electrical nets + Map<ElectricalNet*>* m_nets_; + + //Timing model elements + // Map of all our electrical drivers + Map<ElectricalDriver*>* m_drivers_; + // Map of all our driver multipliers + Map<ElectricalDriverMultiplier*>* m_driver_multipliers_; + // Map of all our electrical loads + Map<ElectricalLoad*>* m_loads_; + // Map of all our idealized delays + Map<ElectricalDelay*>* m_delays_; + + // Map of the event infos + Map<EventInfo*>* m_event_infos_; + + }; // class ElectricalModel +} // namespace DSENT + +#endif // __DSENT_MODEL_ELECTRICALMODEL_H__ + diff --git a/ext/dsent/model/EventInfo.cc b/ext/dsent/model/EventInfo.cc new file mode 100644 index 000000000..6bbe781e5 --- /dev/null +++ b/ext/dsent/model/EventInfo.cc @@ -0,0 +1,86 @@ +#include "model/EventInfo.h" + +#include "model/PortInfo.h" +#include "model/TransitionInfo.h" + +namespace DSENT +{ + EventInfo::EventInfo(const String& event_name_, const Map<PortInfo*>* port_infos_) + : m_event_name_(event_name_) + { + m_trans_info_map_ = new Map<TransitionInfo>; + + // Get the name of each input port and add a transition info for it + Map<PortInfo*>::ConstIterator it_begin = port_infos_->begin(); + Map<PortInfo*>::ConstIterator it_end = port_infos_->end(); + Map<PortInfo*>::ConstIterator it; + for(it = it_begin; it != it_end; ++it) + { + const String& port_name = it->first; + m_trans_info_map_->set(port_name, TransitionInfo()); + } + } + + EventInfo::~EventInfo() + { + delete m_trans_info_map_; + } + + const String& EventInfo::getEventName() const + { + return m_event_name_; + } + + void EventInfo::setTransitionInfo(const String& port_name_, const TransitionInfo& trans_info_) + { + ASSERT(m_trans_info_map_->keyExist(port_name_), "[Error] " + getEventName() + + " -> Port (" + port_name_ + ") does not exist!"); + + m_trans_info_map_->set(port_name_, trans_info_); + return; + } + + void EventInfo::setStaticTransitionInfo(const String& port_name_) + { + ASSERT(m_trans_info_map_->keyExist(port_name_), "[Error] " + getEventName() + + " -> Port (" + port_name_ + ") does not exist!"); + + m_trans_info_map_->set(port_name_, TransitionInfo(0.5, 0.0, 0.5)); + return; + } + + void EventInfo::setRandomTransitionInfos() + { + Map<TransitionInfo>::Iterator it_begin = m_trans_info_map_->begin(); + Map<TransitionInfo>::Iterator it_end = m_trans_info_map_->end(); + Map<TransitionInfo>::Iterator it; + for(it = it_begin; it != it_end; ++it) + { + TransitionInfo& trans_info = it->second; + trans_info = TransitionInfo(); + } + return; + } + + void EventInfo::setStaticTransitionInfos() + { + Map<TransitionInfo>::Iterator it_begin = m_trans_info_map_->begin(); + Map<TransitionInfo>::Iterator it_end = m_trans_info_map_->end(); + Map<TransitionInfo>::Iterator it; + for(it = it_begin; it != it_end; ++it) + { + TransitionInfo& trans_info = it->second; + trans_info = TransitionInfo(0.5, 0.0, 0.5); + } + return; + } + + const TransitionInfo& EventInfo::getTransitionInfo(const String& port_name_) const + { + ASSERT(m_trans_info_map_->keyExist(port_name_), "[Error] " + getEventName() + + " -> Port (" + port_name_ + ") does not exist!"); + + return m_trans_info_map_->get(port_name_); + } +} // namespace DSENT + diff --git a/ext/dsent/model/EventInfo.h b/ext/dsent/model/EventInfo.h new file mode 100644 index 000000000..646a6e18c --- /dev/null +++ b/ext/dsent/model/EventInfo.h @@ -0,0 +1,32 @@ +#ifndef __DSENT_MODEL_EVENT_INFO_H__ +#define __DSENT_MODEL_EVENT_INFO_H__ + +#include "util/CommonType.h" +#include "model/TransitionInfo.h" + +namespace DSENT +{ + class PortInfo; + + class EventInfo + { + public: + EventInfo(const String& event_name_, const Map<PortInfo*>* port_infos_); + ~EventInfo(); + + public: + const String& getEventName() const; + void setTransitionInfo(const String& port_name_, const TransitionInfo& trans_info_); + void setStaticTransitionInfo(const String& port_name_); + void setRandomTransitionInfos(); + void setStaticTransitionInfos(); + const TransitionInfo& getTransitionInfo(const String& port_name_) const; + + private: + String m_event_name_; + Map<TransitionInfo>* m_trans_info_map_; + }; // class EventInfo +} // namespace DSENT + +#endif // __DSENT_MODEL_EVENT_INFO_H__ + diff --git a/ext/dsent/model/Model.cc b/ext/dsent/model/Model.cc new file mode 100644 index 000000000..5a7bfe391 --- /dev/null +++ b/ext/dsent/model/Model.cc @@ -0,0 +1,698 @@ +#include "model/Model.h" + +#include <vector> + +#include "util/Result.h" + +namespace DSENT +{ + using std::vector; + using LibUtil::deletePtrMap; + using LibUtil::clonePtrMap; + + Model::SubModel::SubModel(Model* model_, double num_models_) + : m_model_(model_), m_num_models_(num_models_) + {} + + Model::SubModel::~SubModel() + { + delete m_model_; + } + + Model* Model::SubModel::getModel() + { + return m_model_; + } + + const Model* Model::SubModel::getModel() const + { + return m_model_; + } + + double Model::SubModel::getNumModels() const + { + return m_num_models_; + } + + Model::SubModel* Model::SubModel::clone() const + { + return new SubModel(*this); + } + + Model::SubModel::SubModel(const SubModel& sub_model_) + { + m_model_ = sub_model_.m_model_->clone(); + m_num_models_ = sub_model_.m_num_models_; + } + + const char Model::TYPE_SEPARATOR[] = ">>"; + const char Model::HIERARCHY_SEPARATOR[] = "->"; + const char Model::SUBFIELD_SEPARATOR[] = ":"; + const char Model::DETAIL_SEPARATOR[] = "@"; + + Model::Model(const String& instance_name_, const TechModel* tech_model_) + : m_instance_name_(instance_name_), m_tech_model_(tech_model_), + m_constructed_(false), m_updated_(false), m_evaluated_(false) + { + m_property_names_ = new vector<String>; + m_parameter_names_ = new vector<String>; + m_parameters_ = new ParameterMap(); + m_properties_ = new PropertyMap(); + m_generated_properties_ = new PropertyMap(); + m_sub_instances_ = new Map<SubModel*>(); + m_event_map_ = new Map<Result*>(); + m_area_map_ = new Map<Result*>(); + m_ndd_power_map_ = new Map<Result*>(); + } + + Model::~Model() + { + // Clear parameter names + delete m_parameter_names_; + // Clear property name + delete m_property_names_; + + // Clear parameters + delete m_parameters_; + m_parameters_ = NULL; + // Clear input properties + delete m_properties_; + m_properties_ = NULL; + + // Clear generated properties + delete m_generated_properties_; + m_generated_properties_ = NULL; + + // Clear sub models + deletePtrMap<SubModel>(m_sub_instances_); + m_sub_instances_ = NULL; + + // Clear all results + deletePtrMap<Result>(m_event_map_); + m_event_map_ = NULL; + deletePtrMap<Result>(m_area_map_); + m_area_map_ = NULL; + deletePtrMap<Result>(m_ndd_power_map_); + m_ndd_power_map_ = NULL; + } + + void Model::setInstanceName(const String& instance_name_) + { + m_instance_name_ = instance_name_; + return; + } + + const String& Model::getInstanceName() const + { + return m_instance_name_; + } + + void Model::setIsTopModel(bool is_top_model_) + { + m_is_top_model_ = is_top_model_; + return; + } + + bool Model::getIsTopModel() const + { + return m_is_top_model_; + } + + //------------------------------------------------------------------------- + // Parameters and properties checks + //------------------------------------------------------------------------- + void Model::addParameterName(const String& parameter_name_) + { + ASSERT(!m_constructed_, "[Error] " + getInstanceName() + + " -> Cannot add additional parameters names after model is constructed!"); + m_parameter_names_->push_back(parameter_name_); + + return; + } + + void Model::addParameterName(const String& parameter_name_, const String& parameter_default_) + { + ASSERT(!m_constructed_, "[Error] " + getInstanceName() + + " -> Cannot add additional parameters names after model is constructed!"); + m_parameter_names_->push_back(parameter_name_); + setParameter(parameter_name_, parameter_default_); + return; + } + + const vector<String>* Model::getParameterNames() const + { + return m_parameter_names_; + } + + void Model::addPropertyName(const String& property_name_) + { + ASSERT(!m_constructed_, "[Error] " + getInstanceName() + + " -> Cannot add additional property names after model is constructed!"); + m_property_names_->push_back(property_name_); + return; + } + + void Model::addPropertyName(const String& property_name_, const String& property_default_) + { + ASSERT(!m_constructed_, "[Error] " + getInstanceName() + + " -> Cannot add additional property names after model is constructed!"); + m_property_names_->push_back(property_name_); + setProperty(property_name_, property_default_); + return; + } + + const vector<String>* Model::getPropertyNames() const + { + return m_property_names_; + } + + void Model::checkParameters() const + { + String missing_parameters = ""; + + for(int i = 0; i < (int)m_parameter_names_->size(); ++i) + { + const String& parameter_name = m_parameter_names_->at(i); + if (!m_parameters_->keyExist(parameter_name)) + missing_parameters += " " + parameter_name + "\n"; + } + + ASSERT(missing_parameters.size() == 0, "[Error] " + m_instance_name_ + + " -> Missing parameters:\n" + missing_parameters); + return; + } + + void Model::checkProperties() const + { + String missing_properties = ""; + + for(int i = 0; i < (int)m_property_names_->size(); ++i) + { + const String& property_name = m_property_names_->at(i); + if (!m_properties_->keyExist(property_name)) + missing_properties += " " + property_name + "\n"; + } + + ASSERT(missing_properties.size() == 0, "[Error] " + m_instance_name_ + + " -> Missing properties:\n" + missing_properties); + return; + } + //------------------------------------------------------------------------- + + //------------------------------------------------------------------------- + // Parameters Manipulation + //------------------------------------------------------------------------- + const ParameterMap* Model::getParameters() const + { + return m_parameters_; + } + + const String Model::getParameter(const String& parameter_name_) const + { + return m_parameters_->get(parameter_name_); + } + + void Model::setParameter(const String& parameter_name_, const String& parameter_value_) + { + ASSERT(!m_constructed_, "[Error] " + getInstanceName() + + " -> Cannot set parameters after model is constructed!"); + m_parameters_->set(parameter_name_, parameter_value_); + } + //------------------------------------------------------------------------- + + //------------------------------------------------------------------------- + // Properties Manipulation + //------------------------------------------------------------------------- + const PropertyMap* Model::getProperties() const + { + return m_properties_; + } + + const String Model::getProperty(const String& property_name_) const + { + return m_properties_->get(property_name_); + } + + void Model::setProperty(const String& property_name_, const String& property_value_) + { + // If any properties changed, reset updated and evaluated flags + m_updated_ = false; + m_evaluated_ = false; + m_properties_->set(property_name_, property_value_); + } + //------------------------------------------------------------------------- + + PropertyMap* Model::getGenProperties() + { + return m_generated_properties_; + } + + const PropertyMap* Model::getGenProperties() const + { + return m_generated_properties_; + } + + void Model::addSubInstances(Model* sub_instance_, double num_sub_instances_) + { + // Get instance name + const String& sub_instance_name = sub_instance_->getInstanceName(); + + // Check if the instance exists + if(m_sub_instances_->keyExist(sub_instance_name)) + { + const String& error_msg = "[Error] " + m_instance_name_ + + " -> Instance exists (" + sub_instance_name + ")"; + throw Exception(error_msg); + } + + // Check if the num_sub_instances_ is a positive number + ASSERT((num_sub_instances_ >= 0), "[Error] " + m_instance_name_ + + " -> Invalid number of instance (" + String(num_sub_instances_) + ")"); + + // Add the instance + m_sub_instances_->set(sub_instance_name, new SubModel(sub_instance_, num_sub_instances_)); + return; + } + + Model* Model::getSubInstance(const String& sub_instance_name_) + { + // Throw an Exception if the instance already exists + if(!m_sub_instances_->keyExist(sub_instance_name_)) + { + const String& error_msg = "[Error] " + m_instance_name_ + + " -> Instance not exists (" + sub_instance_name_ + ")"; + throw Exception(error_msg); + } + + return m_sub_instances_->get(sub_instance_name_)->getModel(); + } + + const Model* Model::getSubInstance(const String& sub_instance_name_) const + { + // Throw an Exception if the instance does not exist + if(!m_sub_instances_->keyExist(sub_instance_name_)) + { + const String& error_msg = "[Error] " + m_instance_name_ + + " -> Instance not exists (" + sub_instance_name_ + ")"; + throw Exception(error_msg); + } + + return m_sub_instances_->get(sub_instance_name_)->getModel(); + } + + bool Model::hasSubInstance(const String& sub_instance_name_) const + { + return m_sub_instances_->keyExist(sub_instance_name_); + } + + void Model::addAreaResult(Result* area_) + { + const String& area_name = area_->getName(); + + // Throw an Exception if the area already exists + if(m_area_map_->keyExist(area_name)) + { + const String& error_msg = "Internal error: area (" + area_name + + ") exists"; + throw Exception(error_msg); + } + + // Add the area + m_area_map_->set(area_name, area_); + return; + } + + Result* Model::getAreaResult(const String& area_name_) + { + return m_area_map_->get(area_name_); + } + + const Result* Model::getAreaResult(const String& area_name_) const + { + return m_area_map_->get(area_name_); + } + + bool Model::hasAreaResult(const String& area_name_) const + { + return m_area_map_->keyExist(area_name_); + } + + void Model::addNddPowerResult(Result* ndd_power_) + { + const String& ndd_power_name = ndd_power_->getName(); + + // Throw an Exception if the ndd_power already exists + if(m_ndd_power_map_->keyExist(ndd_power_name)) + { + const String& error_msg = "Internal error: ndd_power (" + ndd_power_name + + ") exists"; + throw Exception(error_msg); + } + + // Add the ndd_power + m_ndd_power_map_->set(ndd_power_name, ndd_power_); + return; + } + + Result* Model::getNddPowerResult(const String& ndd_power_name_) + { + return m_ndd_power_map_->get(ndd_power_name_); + } + + const Result* Model::getNddPowerResult(const String& ndd_power_name_) const + { + return m_ndd_power_map_->get(ndd_power_name_); + } + + bool Model::hasNddPowerResult(const String& ndd_power_name_) const + { + return m_ndd_power_map_->keyExist(ndd_power_name_); + } + + void Model::addEventResult(Result* event_) + { + const String& event_name = event_->getName(); + + // Throw an Exception if the event already exists + if(m_event_map_->keyExist(event_name)) + { + const String& error_msg = "Internal error: event (" + event_name + + ") exists"; + throw Exception(error_msg); + } + + // Add the event + m_event_map_->set(event_name, event_); + return; + } + + Result* Model::getEventResult(const String& event_name_) + { + return m_event_map_->get(event_name_); + } + + const Result* Model::getEventResult(const String& event_name_) const + { + return m_event_map_->get(event_name_); + } + + bool Model::hasEventResult(const String& event_name_) const + { + return m_event_map_->keyExist(event_name_); + } + + const TechModel* Model::getTechModel() const + { + return m_tech_model_; + } + + const void* Model::parseQuery(const String& query_type_, const String& query_hier_, const String& query_sub_field_) + { + // Break query by hierarchy separator + vector<String> hier_split = query_hier_.splitByString(HIERARCHY_SEPARATOR); + + // Check if the query_hier matches the instance name + ASSERT((hier_split[0] == m_instance_name_), "[Error] " + + m_instance_name_ + " -> Mismatch in instance name (" + + hier_split[0] + ")"); + + // If there is no more hierarchy separator, this process the query + if(hier_split.size() == 1) + { + // Query the model + return processQuery(query_type_, query_sub_field_); + } + else + { + // Reconstruct the query + String temp_query_hier = hier_split[1]; + for(int i = 2; i < (int)hier_split.size(); ++i) + { + temp_query_hier += HIERARCHY_SEPARATOR + hier_split[i]; + } + + // Get sub instance's name + const String& temp_sub_instance_name = hier_split[1]; + ASSERT(m_sub_instances_->keyExist(temp_sub_instance_name), "[Error] " + + m_instance_name_ + " -> No sub-instances queried (" + + temp_sub_instance_name + ")"); + + return m_sub_instances_->get(temp_sub_instance_name)->getModel()->parseQuery(query_type_, temp_query_hier, query_sub_field_); + } + } + + const void* Model::processQuery(const String& query_type_, const String& query_sub_field_) + { + if(query_type_ == "Property") + { + return getProperties(); + } + else if(query_type_ == "Parameter") + { + return getParameters(); + } + else if(query_type_.contain("Hier")) + { + return this; + } + else if(query_type_ == "Area") + { + return queryArea(query_sub_field_); + } + else if(query_type_ == "NddPower") + { + return queryNddPower(query_sub_field_); + } + else if(query_type_ == "Energy") + { + return queryEventEnergyCost(query_sub_field_); + } + else + { + const String& error_msg = "[Error] " + m_instance_name_ + " -> Unknown query type (" + query_type_ + ")"; + throw Exception(error_msg); + return NULL; + } + } + + const Result* Model::queryArea(const String& area_name_) const + { + ASSERT(m_area_map_->keyExist(area_name_), "[Error] " + m_instance_name_ + + " -> Unknown queried area name (" + area_name_ + ")"); + return m_area_map_->get(area_name_); + } + + const Result* Model::queryNddPower(const String& ndd_power_name_) + { + ASSERT(m_ndd_power_map_->keyExist(ndd_power_name_), "[Error] " + m_instance_name_ + + " -> Unknown queried ndd power name (" + ndd_power_name_ + ")"); + + use("Idle"); + return m_ndd_power_map_->get(ndd_power_name_); + } + + const Result* Model::queryEventEnergyCost(const String& event_name_) + { + ASSERT(m_event_map_->keyExist(event_name_), "[Error] " + m_instance_name_ + + " -> Unknown queried event name (" + event_name_ + ")"); + + use(event_name_); + return m_event_map_->get(event_name_); + } + + // Update checks whether the model needs updating, whether all properties have been specified, + // and calls updateModel if update is necessary + void Model::construct() + { + // Model should not be constructed yet + ASSERT(!m_constructed_, "[Error] " + getInstanceName() + " -> Cannot construct an already contructed model!"); + // Check if whether all needed parameters are defined + checkParameters(); + constructModel(); + m_constructed_ = true; + m_updated_ = false; + m_evaluated_ = false; + return; + } + + // Update checks whether the model needs updating, whether all properties have been specified, + // and calls updateModel if update is necessary + void Model::update() + { + // Model should be constructed + ASSERT(m_constructed_, "[Error] " + getInstanceName() + " -> Cannot update an unconstructed model!"); + // If the model needs updating (due to property change) + // an update is necessary + if (!m_updated_) + { + // Check if all properties needed exist + checkProperties(); + updateModel(); + m_updated_ = true; + m_evaluated_ = false; + } + return; + } + + // Evaluate checks whether the model needs to be evaluated. + void Model::evaluate() + { + // Model should be constructed + ASSERT(m_constructed_, "[Error] " + getInstanceName() + " -> Cannot evaluate an unconstructed model!"); + // Model should be updated + ASSERT(m_updated_, "[Error] " + getInstanceName() + " -> Cannot evaluate without first updating!"); + // If the model needs evaluating + if (!m_evaluated_) + { + evaluateModel(); + m_evaluated_ = true; + } + + return; + } + + void Model::use(const String& event_name_) + { + useModel(event_name_); + return; + } + + void Model::use() + { + useModel(); + return; + } + + // By default, update model will iterate through all sub-instances and do updateModel on them + void Model::updateModel() + { + Map<SubModel*>::Iterator iter = m_sub_instances_->begin(); + Map<SubModel*>::Iterator end = m_sub_instances_->end(); + while (iter != end) + { + iter->second->getModel()->update(); + iter++; + } + return; + } + + // By default, update model will iterate through all sub-instances and do updateModel on them + void Model::evaluateModel() + { + Map<SubModel*>::Iterator iter = m_sub_instances_->begin(); + Map<SubModel*>::Iterator end = m_sub_instances_->end(); + while (iter != end) + { + iter->second->getModel()->evaluate(); + iter++; + } + return; + } + + void Model::useModel(const String& /* event_name_ */) + {} + + void Model::useModel() + {} + + void Model::printHierarchy(const String& query_type_, const String& query_sub_field_, const String& prepend_str_, int detail_level_, ostream& ost_) const + { + if(query_type_ == "InstHier") + { + ost_ << prepend_str_ << getInstanceName() << endl; + printInstHierarchy(prepend_str_, detail_level_, ost_); + //if(detail_level_ > 0) + //{ + //for(Map<SubModel*>::ConstIterator it = m_sub_instances_->begin(); it != m_sub_instances_->end(); ++it) + //{ + //const Model* sub_model = (it->second)->getModel(); + //String temp_prepend_str = prepend_str_ + " "; + //sub_model->printHierarchy(query_type_, query_sub_field_, temp_prepend_str, detail_level_ - 1, ost_); + //} + //} + } + else + { + const Map<Result*>* result_map; + + if(query_type_ == "AreaHier") + { + result_map = m_area_map_; + } + else if(query_type_ == "NddPowerHier") + { + result_map = m_ndd_power_map_; + } + else if(query_type_ == "EventHier") + { + result_map = m_event_map_; + } + else + { + const String& error_msg = "[Error] " + m_instance_name_ + " -> Unknown query type (" + query_type_ + ")"; + throw Exception(error_msg); + return; + } + + if(query_sub_field_ == "") + { + for(Map<Result*>::ConstIterator it = result_map->begin(); it != result_map->end(); ++it) + { + const Result* result = it->second; + ost_ << prepend_str_ << getInstanceName() << "->" << result->getName() << endl; + result->printHierarchy(prepend_str_, detail_level_, ost_); + } + } + else + { + const Result* result = result_map->get(query_sub_field_); + ost_ << prepend_str_ << getInstanceName() << "->" << result->getName() << endl; + result->printHierarchy(prepend_str_, detail_level_, ost_); + } + } + return; + } + + void Model::printInstHierarchy(const String& prepend_str_, int detail_level_, ostream& ost_) const + { + if(detail_level_ > 0) + { + for(Map<SubModel*>::ConstIterator it = m_sub_instances_->begin(); it != m_sub_instances_->end(); ++it) + { + const Model* sub_model = it->second->getModel(); + String temp_prepend_str = prepend_str_ + " "; + + ost_ << prepend_str_ << " |--" << sub_model->getInstanceName() << endl; + sub_model->printInstHierarchy(temp_prepend_str, detail_level_ - 1, ost_); + } + } + return; + } + + Model* Model::clone() const + { + throw Exception(getInstanceName() + " -> Cannot be cloned!"); + } + + Model::Model(const Model& model_) + { + // Copy instance's name + m_instance_name_ = model_.m_instance_name_; + + // Clone properties + m_properties_ = model_.m_properties_->clone(); + + // Clone instances + m_sub_instances_ = clonePtrMap(model_.m_sub_instances_); + + // Clone events, area, ndd_power + m_event_map_ = clonePtrMap(model_.m_event_map_); + m_area_map_ = clonePtrMap(model_.m_area_map_); + m_ndd_power_map_ = clonePtrMap(model_.m_ndd_power_map_); + + // Copy tech model pointer + m_tech_model_ = model_.m_tech_model_; + } + +} // namespace DSENT + diff --git a/ext/dsent/model/Model.h b/ext/dsent/model/Model.h new file mode 100644 index 000000000..9e516d584 --- /dev/null +++ b/ext/dsent/model/Model.h @@ -0,0 +1,223 @@ +#ifndef __DSENT_MODEL_MODEL_H__ +#define __DSENT_MODEL_MODEL_H__ + +#include <vector> + +#include "util/CommonType.h" + +namespace DSENT +{ + using std::vector; + + class TechModel; + class Result; + + // Base class for all the models + class Model + { + protected: + class SubModel + { + public: + SubModel(Model* model_, double num_models_); + ~SubModel(); + + public: + Model* getModel(); + const Model* getModel() const; + double getNumModels() const; + + SubModel* clone() const; + + protected: + SubModel(const SubModel& sub_model_); + + private: + // Pointer to the actual model instance + Model* m_model_; + // Number of models are added + double m_num_models_; + }; + + public: + // Model Constants + static const char TYPE_SEPARATOR[]; + static const char HIERARCHY_SEPARATOR[]; + static const char SUBFIELD_SEPARATOR[]; + static const char DETAIL_SEPARATOR[]; + + public: + Model(const String& instance_name_, const TechModel* tech_model_); + virtual ~Model(); + + public: + // Set the name of this instance + void setInstanceName(const String& instance_name_); + // Get the name of this instance + const String& getInstanceName() const; + + // Set if the model is the top model + void setIsTopModel(bool is_top_model_); + bool getIsTopModel() const; + + // Add a parameter name (with and without default) + void addParameterName(const String& parameter_name_); + void addParameterName(const String& parameter_name_, const String& parameter_default_); + const vector<String>* getParameterNames() const; + + // Add a property name + void addPropertyName(const String& property_name_); + void addPropertyName(const String& property_name_, const String& property_default_); + const vector<String>* getPropertyNames() const; + + // Check if all parameters needed exist in the m_parameters_ + void checkParameters() const; + // Check if all properties needed exist in the m_properties_ + void checkProperties() const; + + // Get the pointer to parameters + const ParameterMap* getParameters() const; + const String getParameter(const String& parameter_name_) const; + void setParameter(const String& parameter_name_, const String& parameter_value_); + + // Get the pointer to properties + const PropertyMap* getProperties() const; + const String getProperty(const String& property_name_) const; + void setProperty(const String& property_name_, const String& property_value_); + + // Get the pointer to generated properties + PropertyMap* getGenProperties(); + const PropertyMap* getGenProperties() const; + + // Add an instance to this model. num_sub_instances_ specifies the + // number of the same instance is added. + void addSubInstances(Model* sub_instance_, double num_sub_instances_); + // Get an instance by name. + Model* getSubInstance(const String& sub_instance_name_); + const Model* getSubInstance(const String& sub_instance_name_) const; + // Check if an instance exists + bool hasSubInstance(const String& sub_instance_name_) const; + + // Add a new area + void addAreaResult(Result* area_); + // Get the pointer to an area. The area is specified by name. + Result* getAreaResult(const String& area_name_); + const Result* getAreaResult(const String& area_name_) const; + // Check if an area exists + bool hasAreaResult(const String& area_name_) const; + + // Add a new ndd_power + void addNddPowerResult(Result* ndd_power_); + // Get the pointer to an ndd_power. The ndd_power is specified by name. + Result* getNddPowerResult(const String& ndd_power_name_); + const Result* getNddPowerResult(const String& ndd_power_name_) const; + // Check if a ndd_power exists + bool hasNddPowerResult(const String& ndd_power_name_) const; + + // Add a new event + void addEventResult(Result* event_); + // Get the pointer to an event. The event is specified by name. + Result* getEventResult(const String& event_name_); + const Result* getEventResult(const String& event_name_) const; + // Check if an event exists + bool hasEventResult(const String& event_name_) const; + + // Get the pointer to the TechModel. + const TechModel* getTechModel() const; + + // Clone and return a new instance + virtual Model* clone() const; + + // Checks to make sure all required parameters are present, makes sure that the model + // has not been constructed yet, and calls constructModel. This function is not meant + // to be overwritten by child classes; constructModel should be overwritten instead + void construct(); + // Update checks whether the model needs updating, whether all properties have been specified, + // and calls updateModel if update is necessary. This function is not meant + // to be overwritten by child classes; updateModel should be overwritten instead + void update(); + // Evaluate checks whether the model needs to be evaluated. Note that this function is + // not meant to be overwritten by child classes; evaluateModel should be overwritten + // instead + void evaluate(); + void use(const String& event_name_); + void use(); + + // Resolve query hierarchy and process query + const void* parseQuery(const String& query_type_, const String& query_hier_, const String& query_sub_field_); + // Process the query + virtual const void* processQuery(const String& query_type_, const String& query_sub_field_); + + // Print hierarchically + void printHierarchy(const String& query_type_, const String& query_sub_field_, const String& prepend_str_, int detail_level_, ostream& ost_) const; + void printInstHierarchy(const String& prepend_str_, int detail_level_, ostream& ost_) const; + + protected: + // Query area + const Result* queryArea(const String& area_name_) const; + // Query non-data-dependent power + const Result* queryNddPower(const String& ndd_power_name_); + // Query event energy cost + const Result* queryEventEnergyCost(const String& event_name_); + + // Constructs the model + virtual void constructModel() = 0; + // Updates timing related information of the model + virtual void updateModel(); + // Evaluate non data dependent power of the model + virtual void evaluateModel(); + virtual void useModel(const String& event_name_); + virtual void useModel(); + + private: + // Private copy constructor. Use clone to perform copy operation. + Model(const Model& model_); + + private: + // Name of this instance + String m_instance_name_; + // Set if this model is the top model + bool m_is_top_model_; + + // Contains the parameters of a model + // Parameters are needed in order to constructModel() and CANNOT be + // changed after constructModel() has been called + ParameterMap* m_parameters_; + // Contains the names of all model parameters + vector<String>* m_parameter_names_; + // Contains the properties of a model + // Properties are required in order to updateModel() and CAN be + // changed be changed after constructModel(). Call updateModel() + // after properties have been changed to use the new properties + PropertyMap* m_properties_; + // Contains the property names needed to update the model + vector<String>* m_property_names_; + // Contains generated properties of the model + // Generated properties are used mostly as a scratch space for + // variables used in the model that must be passed from one + // function to another + PropertyMap* m_generated_properties_; + + // Contains the instances of this model + Map<SubModel*>* m_sub_instances_; + // Contains the area resulst of a model + Map<Result*>* m_area_map_; + // Contains the noo power results of a model + Map<Result*>* m_ndd_power_map_; + // Contains the event results of a model + Map<Result*>* m_event_map_; + // Pointer to a TechModel which contains the technology information + const TechModel* m_tech_model_; + + // Set when a model is constructed + bool m_constructed_; + // Set when a model is updated + bool m_updated_; + // Set when a model is evaluated + bool m_evaluated_; + + }; // class Model +} // namespace DSENT + +#endif // __DSENT_MODEL_MODEL_H__ + diff --git a/ext/dsent/model/ModelGen.cc b/ext/dsent/model/ModelGen.cc new file mode 100644 index 000000000..06957d6fd --- /dev/null +++ b/ext/dsent/model/ModelGen.cc @@ -0,0 +1,306 @@ +#include "model/ModelGen.h" + +#include <iostream> + +#include "model/Model.h" +// Standard cells +#include "model/std_cells/StdCell.h" +#include "model/std_cells/INV.h" +#include "model/std_cells/NAND2.h" +#include "model/std_cells/NOR2.h" +#include "model/std_cells/MUX2.h" +#include "model/std_cells/XOR2.h" +#include "model/std_cells/DFFQ.h" +#include "model/std_cells/LATQ.h" +#include "model/std_cells/ADDF.h" +#include "model/std_cells/OR2.h" +#include "model/std_cells/AND2.h" +#include "model/std_cells/BUF.h" +// Electrical functional units +#include "model/electrical/TestModel.h" +#include "model/electrical/RippleAdder.h" +#include "model/electrical/Multiplexer.h" +#include "model/electrical/MultiplexerCrossbar.h" +#include "model/electrical/OR.h" +#include "model/electrical/Decoder.h" +#include "model/electrical/DFFRAM.h" +#include "model/electrical/MatrixArbiter.h" +#include "model/electrical/SeparableAllocator.h" +#include "model/electrical/router/Router.h" +#include "model/electrical/RepeatedLink.h" +#include "model/electrical/BroadcastHTree.h" +// Optical functional units +#include "model/optical/OpticalLinkBackendTx.h" +#include "model/optical/OpticalLinkBackendRx.h" +#include "model/optical/SWMRLink.h" +#include "model/optical/SWSRLink.h" +#include "model/optical/LaserSource.h" +#include "model/optical/ThrottledLaserSource.h" +#include "model/optical/RingModulator.h" +#include "model/optical/RingDetector.h" +// Networks +#include "model/network/ElectricalMesh.h" +#include "model/network/ElectricalClos.h" +#include "model/network/PhotonicClos.h" + +namespace DSENT +{ + using std::cout; + using std::endl; + + //TODO: Eventually automate the creation of this file + + Model* ModelGen::createModel(const String& model_name_, const String& instance_name_, const TechModel* tech_model_) + { + Log::printLine("ModelGen::createModel -> " + model_name_); + + if("INV" == model_name_) + { + return new INV(instance_name_, tech_model_); + } + else if("NAND2" == model_name_) + { + return new NAND2(instance_name_, tech_model_); + } + else if("NOR2" == model_name_) + { + return new NOR2(instance_name_, tech_model_); + } + else if("MUX2" == model_name_) + { + return new MUX2(instance_name_, tech_model_); + } + else if("XOR2" == model_name_) + { + return new XOR2(instance_name_, tech_model_); + } + else if("DFFQ" == model_name_) + { + return new DFFQ(instance_name_, tech_model_); + } + else if("LATQ" == model_name_) + { + return new LATQ(instance_name_, tech_model_); + } + else if("ADDF" == model_name_) + { + return new ADDF(instance_name_, tech_model_); + } + else if("OR2" == model_name_) + { + return new OR2(instance_name_, tech_model_); + } + else if("AND2" == model_name_) + { + return new AND2(instance_name_, tech_model_); + } + else if("BUF" == model_name_) + { + return new BUF(instance_name_, tech_model_); + } + else if("TestModel" == model_name_) + { + return new TestModel(instance_name_, tech_model_); + } + else if("RippleAdder" == model_name_) + { + return new RippleAdder(instance_name_, tech_model_); + } + else if("Multiplexer" == model_name_) + { + return new Multiplexer(instance_name_, tech_model_); + } + else if("OR" == model_name_) + { + return new OR(instance_name_, tech_model_); + } + else if("MultiplexerCrossbar" == model_name_) + { + return new MultiplexerCrossbar(instance_name_, tech_model_); + } + else if("Decoder" == model_name_) + { + return new Decoder(instance_name_, tech_model_); + } + else if("DFFRAM" == model_name_) + { + return new DFFRAM(instance_name_, tech_model_); + } + else if("MatrixArbiter" == model_name_) + { + return new MatrixArbiter(instance_name_, tech_model_); + } + else if("SeparableAllocator" == model_name_) + { + return new SeparableAllocator(instance_name_, tech_model_); + } + else if("Router" == model_name_) + { + return new Router(instance_name_, tech_model_); + } + else if("OpticalLinkBackendTx" == model_name_) + { + return new OpticalLinkBackendTx(instance_name_, tech_model_); + } + else if("OpticalLinkBackendRx" == model_name_) + { + return new OpticalLinkBackendRx(instance_name_, tech_model_); + } + else if("SWMRLink" == model_name_) + { + return new SWMRLink(instance_name_, tech_model_); + } + else if("SWSRLink" == model_name_) + { + return new SWSRLink(instance_name_, tech_model_); + } + else if("LaserSource" == model_name_) + { + return new LaserSource(instance_name_, tech_model_); + } + else if("ThrottledLaserSource" == model_name_) + { + return new ThrottledLaserSource(instance_name_, tech_model_); + } + else if("RingModulator" == model_name_) + { + return new RingModulator(instance_name_, tech_model_); + } + else if("RingDetector" == model_name_) + { + return new RingDetector(instance_name_, tech_model_); + } + else if("RepeatedLink" == model_name_) + { + return new RepeatedLink(instance_name_, tech_model_); + } + else if("BroadcastHTree" == model_name_) + { + return new BroadcastHTree(instance_name_, tech_model_); + } + else if("ElectricalMesh" == model_name_) + { + return new ElectricalMesh(instance_name_, tech_model_); + } + else if("ElectricalClos" == model_name_) + { + return new ElectricalClos(instance_name_, tech_model_); + } + else if("PhotonicClos" == model_name_) + { + return new PhotonicClos(instance_name_, tech_model_); + } + else + { + const String& error_msg = "[Error] Invalid model name (" + model_name_ + ")"; + throw Exception(error_msg); + return NULL; + } + return NULL; + } + + StdCell* ModelGen::createStdCell(const String& std_cell_name_, const String& instance_name_, const TechModel* tech_model_) + { + Log::printLine("ModelGen::createStdCell -> " + std_cell_name_); + + if("INV" == std_cell_name_) + { + return new INV(instance_name_, tech_model_); + } + else if("NAND2" == std_cell_name_) + { + return new NAND2(instance_name_, tech_model_); + } + else if("NOR2" == std_cell_name_) + { + return new NOR2(instance_name_, tech_model_); + } + else if("MUX2" == std_cell_name_) + { + return new MUX2(instance_name_, tech_model_); + } + else if("XOR2" == std_cell_name_) + { + return new XOR2(instance_name_, tech_model_); + } + else if("DFFQ" == std_cell_name_) + { + return new DFFQ(instance_name_, tech_model_); + } + else if("LATQ" == std_cell_name_) + { + return new LATQ(instance_name_, tech_model_); + } + else if("ADDF" == std_cell_name_) + { + return new ADDF(instance_name_, tech_model_); + } + else if("OR2" == std_cell_name_) + { + return new OR2(instance_name_, tech_model_); + } + else if("AND2" == std_cell_name_) + { + return new AND2(instance_name_, tech_model_); + } + else if("BUF" == std_cell_name_) + { + return new BUF(instance_name_, tech_model_); + } + else + { + const String& error_msg = "[Error] Invalid Standard Cell name (" + std_cell_name_ + ")"; + throw Exception(error_msg); + return NULL; + } + return NULL; + } + + ElectricalModel* ModelGen::createRAM(const String& ram_name_, const String& instance_name_, const TechModel* tech_model_) + { + Log::printLine("ModelGen::createRAM -> " + ram_name_); + + if("DFFRAM" == ram_name_) + { + return new DFFRAM(instance_name_, tech_model_); + } + else + { + const String& error_msg = "[Error] Invalid RAM name (" + ram_name_ + ")"; + throw Exception(error_msg); + return NULL; + } + return NULL; + } + + ElectricalModel* ModelGen::createCrossbar(const String& crossbar_name_, const String& instance_name_, const TechModel* tech_model_) + { + Log::printLine("ModelGen::createCrossbar -> " + crossbar_name_); + + if("MultiplexerCrossbar" == crossbar_name_) + { + return new MultiplexerCrossbar(instance_name_, tech_model_); + } + else + { + const String& error_msg = "[Error] Invalid Crossbar name (" + crossbar_name_ + ")"; + throw Exception(error_msg); + return NULL; + } + return NULL; + } + //----------------------------------------------------------------- + + void ModelGen::printAvailableModels() + { + // TODO: Need more descriptions + cout << "INV NAND2 NOR2 MUX2 XOR2 DFFQ LATQ ADDF OR2 AND2 BUF" << endl; + cout << "RippleAdder Multiplexer OR RepeatedLink BroadcastHTree" << endl; + cout << "MultiplexerCrossbar Decoder DFFRAM MatrixArbiter SeparableAllocator Router" << endl; + cout << "OpticalLinkBackendTx OpticalLinkBackendRx SWMRLink SWSRLink" << endl; + cout << "LaserSource ThrottledLaserSource RingModulator RingDetector" << endl; + cout << "ElectricalMesh ElectricalClos PhotonicClos" << endl; + return; + } +} // namespace DSENT + diff --git a/ext/dsent/model/ModelGen.h b/ext/dsent/model/ModelGen.h new file mode 100644 index 000000000..c11f435d5 --- /dev/null +++ b/ext/dsent/model/ModelGen.h @@ -0,0 +1,30 @@ +#ifndef __DSENT_MODEL_MODELGEN_H__ +#define __DSENT_MODEL_MODELGEN_H__ + +#include "util/CommonType.h" + +namespace DSENT +{ + class Model; + class ElectricalModel; + class StdCell; + class TechModel; + + class ModelGen + { + public: + // Create the model corresponding to the given String + static Model* createModel(const String& model_name_, const String& instance_name_, const TechModel* tech_model_); + // Create the standard cell corresponding to the given String + static StdCell* createStdCell(const String& std_cell_name_, const String& instance_name_, const TechModel* tech_model_); + // Create the ram corresponding to the given String + static ElectricalModel* createRAM(const String& ram_name_, const String& instance_name_, const TechModel* tech_model_); + // Create the crossbar corresponding to the given String + static ElectricalModel* createCrossbar(const String& crossbar_name_, const String& instance_name_, const TechModel* tech_model_); + // Print the available models + static void printAvailableModels(); + }; +} // namespace DSENT + +#endif // __DSENT_MODEL_MODELGEN_H__ + diff --git a/ext/dsent/model/OpticalModel.cc b/ext/dsent/model/OpticalModel.cc new file mode 100644 index 000000000..7236d6bda --- /dev/null +++ b/ext/dsent/model/OpticalModel.cc @@ -0,0 +1,277 @@ +#include "model/OpticalModel.h" + +#include "model/PortInfo.h" +#include "model/EventInfo.h" +#include "model/optical_graph/OpticalWaveguide.h" +#include "model/optical_graph/OpticalNode.h" +#include "model/optical_graph/OpticalLaser.h" +#include "model/optical_graph/OpticalModulator.h" +#include "model/optical_graph/OpticalFilter.h" +#include "model/optical_graph/OpticalDetector.h" +#include "model/optical_graph/OpticalWavelength.h" + +namespace DSENT +{ + OpticalModel::OpticalModel(const String& instance_name_, const TechModel* tech_model_) + : ElectricalModel(instance_name_, tech_model_) + { + m_optical_input_ports_ = new Map<PortInfo*>; + m_optical_output_ports_ = new Map<PortInfo*>; + + m_waveguides_ = new Map<OpticalWaveguide*>; + m_lasers_ = new Map<OpticalLaser*>; + m_modulators_ = new Map<OpticalModulator*>; + m_filters_ = new Map<OpticalFilter*>; + m_detectors_ = new Map<OpticalDetector*>; + } + + OpticalModel::~OpticalModel() + { + delete m_optical_input_ports_; + delete m_optical_output_ports_; + deletePtrMap<OpticalWaveguide>(m_waveguides_); + deletePtrMap<OpticalLaser>(m_lasers_); + deletePtrMap<OpticalModulator>(m_modulators_); + deletePtrMap<OpticalFilter>(m_filters_); + deletePtrMap<OpticalDetector>(m_detectors_); + m_optical_input_ports_ = NULL; + m_optical_output_ports_ = NULL; + m_waveguides_ = NULL; + m_lasers_ = NULL; + m_modulators_ = NULL; + m_filters_ = NULL; + m_detectors_ = NULL; + } + + // Connect an optical port (input or output) to some OpticalWaveguide + void OpticalModel::opticalPortConnect(OpticalModel* connect_model_, const String& port_name_, const String& waveguide_name_) + { + // Check that the connecting waveguide exists + ASSERT(m_waveguides_->keyExist(waveguide_name_), "[Error] " + getInstanceName() + + " -> Waveguide '" + waveguide_name_ + "' does not exist!"); + + // Check whether the port name is an input or output, assertion error if neither + bool is_input = connect_model_->getOpticalInputs()->keyExist(port_name_); + bool is_output = connect_model_->getOpticalOutputs()->keyExist(port_name_); + ASSERT(is_input || is_output, "[Error] " + getInstanceName() + " -> Model '" + connect_model_->getInstanceName() + + "' does not have a port named '" + port_name_ + "'!"); + + // Get the two waveguides + OpticalWaveguide* port_waveguide = connect_model_->getWaveguide(port_name_); + OpticalWaveguide* connect_waveguide = getWaveguide(waveguide_name_); + + // Check that the two waveguides expect the same wavelengths + ASSERT((port_waveguide->getWavelengths().first == connect_waveguide->getWavelengths().first) && + (port_waveguide->getWavelengths().second == connect_waveguide->getWavelengths().second), + "[Error] " + getInstanceName() + " -> Optical port expects different wavelengths for Model '" + + connect_model_->getInstanceName() + "." + port_name_ + "' and waveguide '" + waveguide_name_ + "'!"); + + if(is_input) + { + connect_waveguide->addDownstreamNode(port_waveguide); + } + else if(is_output) + { + port_waveguide->addDownstreamNode(connect_waveguide); + } + } + + //Get Waveguides + const Map<OpticalWaveguide*>* OpticalModel::getWaveguides() const + { + return m_waveguides_; + } + + OpticalWaveguide* OpticalModel::getWaveguide(const String& name_) + { + return m_waveguides_->get(name_); + } + + //Get Lasers + const Map<OpticalLaser*>* OpticalModel::getLasers() const + { + return m_lasers_; + } + + OpticalLaser* OpticalModel::getLaser(const String& name_) + { + return m_lasers_->get(name_); + } + + //Get Modulators + const Map<OpticalModulator*>* OpticalModel::getModulators() const + { + return m_modulators_; + } + + OpticalModulator* OpticalModel::getModulator(const String& name_) + { + return m_modulators_->get(name_); + } + + //Get Filters + const Map<OpticalFilter*>* OpticalModel::getFilters() const + { + return m_filters_; + } + + OpticalFilter* OpticalModel::getFilter(const String& name_) + { + return m_filters_->get(name_); + } + + //Get Detectors + const Map<OpticalDetector*>* OpticalModel::getDetectors() const + { + return m_detectors_; + } + + OpticalDetector* OpticalModel::getDetector(const String& name_) + { + return m_detectors_->get(name_); + } + + //Get Inputs + const Map<PortInfo*>* OpticalModel::getOpticalInputs() const + { + return m_optical_input_ports_; + } + + PortInfo* OpticalModel::getOpticalInputPort(const String& name_) + { + ASSERT(m_optical_input_ports_->keyExist(name_), "[Error] " + getInstanceName() + + " -> Input port (" + name_ + ") does not exist"); + + return m_optical_input_ports_->get(name_); + } + + const PortInfo* OpticalModel::getOpticalInputPort(const String& name_) const + { + ASSERT(m_optical_input_ports_->keyExist(name_), "[Error] " + getInstanceName() + + " -> Input port (" + name_ + ") does not exist"); + + return m_optical_input_ports_->get(name_); + } + + //Get Outputs + const Map<PortInfo*>* OpticalModel::getOpticalOutputs() const + { + return m_optical_output_ports_; + } + + PortInfo* OpticalModel::getOpticalOutputPort(const String& name_) + { + ASSERT(m_optical_output_ports_->keyExist(name_), "[Error] " + getInstanceName() + + " -> Input port (" + name_ + ") does not exist"); + + return m_optical_output_ports_->get(name_); + } + + const PortInfo* OpticalModel::getOpticalOutputPort(const String& name_) const + { + ASSERT(m_optical_output_ports_->keyExist(name_), "[Error] " + getInstanceName() + + " -> Input port (" + name_ + ") does not exist"); + + return m_optical_output_ports_->get(name_); + } + + //------------------------------------------------------------------------- + // Optical Connectivity Creation Functions + //------------------------------------------------------------------------- + void OpticalModel::createOpticalInputPort(const String& name_, const WavelengthGroup& wavelength_group_) + { + // Create the new waveguides + // This should already check that it has not been previously declared + createWaveguide(name_, wavelength_group_); + // Add the waveguide name to list of input ports + m_optical_input_ports_->set(name_, new PortInfo(name_, wavelength_group_)); + return; + } + + void OpticalModel::createOpticalOutputPort(const String& name_, const WavelengthGroup& wavelength_group_) + { + // Create the new waveguides (including its waveguide reference) + // This should already check that it has not been previously declared + createWaveguide(name_, wavelength_group_); + // Add the waveguide name to list of output ports + m_optical_output_ports_->set(name_, new PortInfo(name_, wavelength_group_)); + return; + } + + // Waveguide creation + void OpticalModel::createWaveguide(const String& name_, const WavelengthGroup& wavelengths_) + { + // Check that the waveguide hasn't been previously declared + ASSERT( !m_waveguides_->keyExist(name_), "[Error] " + getInstanceName() + + " -> Redeclaration of waveguide " + name_); + m_waveguides_->set(name_, new OpticalWaveguide(name_, this, wavelengths_)); + return; + } + + // Laser creation + void OpticalModel::createLaser(const String& name_, const WavelengthGroup& wavelengths_) + { + // Check that the laser hasn't been previously declared + ASSERT( !m_lasers_->keyExist(name_), "[Error] " + getInstanceName() + + " -> Redeclaration of laser " + name_); + m_lasers_->set(name_, new OpticalLaser(name_, this, wavelengths_)); + return; + } + + // Modulator creation + void OpticalModel::createModulator(const String& name_, const WavelengthGroup& wavelengths_, bool opt_loss_, OpticalTransmitter* transmitter_) + { + // Check that the modulator hasn't been previously declared + ASSERT( !m_modulators_->keyExist(name_), "[Error] " + getInstanceName() + + " -> Redeclaration of modulator " + name_); + m_modulators_->set(name_, new OpticalModulator(name_, this, wavelengths_, opt_loss_, transmitter_)); + return; + } + + // Modulator Multiplier creation + void OpticalModel::createFilter(const String& name_, const WavelengthGroup& wavelengths_, bool drop_all_, const WavelengthGroup& drop_wavelengths_) + { + // Check that the filter hasn't been previously declared + ASSERT( !m_filters_->keyExist(name_), "[Error] " + getInstanceName() + + " -> Redeclaration of filter " + name_); + m_filters_->set(name_, new OpticalFilter(name_, this, wavelengths_, drop_all_, drop_wavelengths_)); + return; + } + + // Detector creation + void OpticalModel::createDetector(const String& name_, const WavelengthGroup& wavelengths_, OpticalReceiver* receiver_) + { + // Check that the detector hasn't been previously declared + ASSERT( !m_detectors_->keyExist(name_), "[Error] " + getInstanceName() + + " -> Redeclaration of detector " + name_); + m_detectors_->set(name_, new OpticalDetector(name_, this, wavelengths_, receiver_)); + return; + } + + //------------------------------------------------------------------------- + + // Assign a waveguide to be downstream from another waveguide + // assign downtream_waveguide_name_ = upstream_waveguide_name_ + void OpticalModel::opticalAssign(const String& downstream_waveguide_name_, const String& upstream_waveguide_name_) + { + ASSERT(getWaveguides()->keyExist(downstream_waveguide_name_), "[Error] " + getInstanceName() + " -> Waveguide '" + + downstream_waveguide_name_ + "' does not exist!"); + + ASSERT(getWaveguides()->keyExist(upstream_waveguide_name_), "[Error] " + getInstanceName() + " -> Waveguide '" + + upstream_waveguide_name_ + "' does not exist!"); + + // Get the two waveguides + OpticalWaveguide* upstream_waveguide = getWaveguide(upstream_waveguide_name_); + OpticalWaveguide* downstream_waveguide = getWaveguide(downstream_waveguide_name_); + + // Check that the two waveguides expect the same wavelengths + ASSERT((upstream_waveguide->getWavelengths().first == downstream_waveguide->getWavelengths().first) && + (upstream_waveguide->getWavelengths().second == downstream_waveguide->getWavelengths().second), + "[Error] " + getInstanceName() + " -> Assignment expects different wavelengths for waveguide '" + + upstream_waveguide_name_ + "' and waveguide '" + downstream_waveguide_name_ + "'!"); + + // Connect the downstream waveguide and the upstream waveguide + upstream_waveguide->addDownstreamNode(downstream_waveguide); + return; + } +} // namespace DSENT diff --git a/ext/dsent/model/OpticalModel.h b/ext/dsent/model/OpticalModel.h new file mode 100644 index 000000000..0b4f27d37 --- /dev/null +++ b/ext/dsent/model/OpticalModel.h @@ -0,0 +1,143 @@ +#ifndef __DSENT_MODEL_OPTICALMODEL_H__ +#define __DSENT_MODEL_OPTICALMODEL_H__ + +#include "util/CommonType.h" +#include "model/ElectricalModel.h" + +namespace DSENT +{ + class PortInfo; + class EventInfo; + class OpticalWaveguide; + class OpticalLaser; + class OpticalFilter; + class OpticalModulator; + class OpticalDetector; + class OpticalReceiver; + class OpticalTransmitter; + + // A Wavelength group consisting of start and end wavelength indices + // Assuming it is the same as a net index so I can use the PortInfo class + typedef NetIndex WavelengthGroup; + + // Helper function for making waveguide groups + inline WavelengthGroup makeWavelengthGroup(int start_index_, int end_index_) + { + ASSERT(end_index_ >= start_index_, (String) "[Error] Invalid wavelength group range " + + "[" + (String) start_index_ + ":" + (String) end_index_ + "]"); + + return WavelengthGroup(start_index_, end_index_); + } + + // Helper function for making wavelength groups + inline WavelengthGroup makeWavelengthGroup(int index_) + { + return makeWavelengthGroup(index_, index_); + } + + // OpticalModel specifies optical connectivity to other optical models as well + class OpticalModel : public ElectricalModel + { + + public: + OpticalModel(const String& instance_name_, const TechModel* tech_model_); + virtual ~OpticalModel(); + + public: + //----------------------------------------------------------------- + // Connectivity specification + //----------------------------------------------------------------- + + /* + + // Waveguide multiplier + void setWaveguideMultiplier(unsigned int waveguide_multiplier_); + unsigned int getWaveguideMultiplier(); + + */ + // Input Ports + void createOpticalInputPort(const String& name_, const WavelengthGroup& wavelengths_); + const Map<PortInfo*>* getOpticalInputs() const; + PortInfo* getOpticalInputPort(const String& name_); + const PortInfo* getOpticalInputPort(const String& name_) const; + + // Output Ports + void createOpticalOutputPort(const String& name_, const WavelengthGroup& wavelengths_); + const Map<PortInfo*>* getOpticalOutputs() const; + PortInfo* getOpticalOutputPort(const String& name_); + const PortInfo* getOpticalOutputPort(const String& name_) const; + + // Optical Waveguides + void createWaveguide(const String& name_, const WavelengthGroup& wavelengths_); + const Map<OpticalWaveguide*>* getWaveguides() const; + OpticalWaveguide* getWaveguide(const String& name_); + + // Assign a waveguide to be downstream from another waveguide + void opticalAssign(const String& downstream_waveguide_name_, const String& upstream_waveguide_name_); + + // Connect a port (input or output) to some waveguide + void opticalPortConnect(OpticalModel* connect_model_, const String& connect_port_name_, const String& connect_waveguide_name_); + //----------------------------------------------------------------- + + //----------------------------------------------------------------- + // Optical Graph Model Components + //----------------------------------------------------------------- + // Optical Laser Sources + + void createLaser(const String& name_, const WavelengthGroup& wavelengths_); + const Map<OpticalLaser*>* getLasers() const; + OpticalLaser* getLaser(const String& name_); + // Optical Laser Sources + void createFilter(const String& name_, const WavelengthGroup& wavelengths_, bool drop_all_, const WavelengthGroup& drop_wavelengths_); + const Map<OpticalFilter*>* getFilters() const; + OpticalFilter* getFilter(const String& name_); + // Optical Modulators + void createModulator(const String& name_, const WavelengthGroup& wavelengths_, bool opt_loss_, OpticalTransmitter* transmitter_); + const Map<OpticalModulator*>* getModulators() const; + OpticalModulator* getModulator(const String& name_); + // Optical Detectors + void createDetector(const String& name_, const WavelengthGroup& wavelengths_, OpticalReceiver* receiver_); + const Map<OpticalDetector*>* getDetectors() const; + OpticalDetector* getDetector(const String& name_); + + //----------------------------------------------------------------- + + protected: + // In an OpticalModel, the complete optical port-to-port connectivity + // of all sub-instances must be specified. Addition/Removal optical + // ports or port-related nets cannot happen after this step + //virtual void constructModel() = 0; + // In an OpticalModel, updateModel MUST finish all necessary + // calculations such that loss and wavelength power can be calculated + //virtual void updateModel() = 0; + // In an OpticalModel, evaluateModel should calculate all wavelength + // power, updating power and energy events as necessary + //virtual void evaluateModel() = 0; + + private: + // Private copy constructor. Use clone to perform copy operation. + OpticalModel(const OpticalModel& model_); + + private: + // Map of all input ports + Map<PortInfo*>* m_optical_input_ports_; + // Map of all output ports + Map<PortInfo*>* m_optical_output_ports_; + + // Optical graph model elements + // Map of all waveguides + Map<OpticalWaveguide*>* m_waveguides_; + // Map of all laser source elements + Map<OpticalLaser*>* m_lasers_; + // Map of all filter elements + Map<OpticalFilter*>* m_filters_; + // Map of all modulator elements + Map<OpticalModulator*>* m_modulators_; + // Map of all photodetector elements + Map<OpticalDetector*>* m_detectors_; + + }; // class OpticalModel +} // namespace DSENT + +#endif // __DSENT_MODEL_OPTICALMODEL_H__ + diff --git a/ext/dsent/model/PortInfo.cc b/ext/dsent/model/PortInfo.cc new file mode 100644 index 000000000..fd859fc7b --- /dev/null +++ b/ext/dsent/model/PortInfo.cc @@ -0,0 +1,35 @@ +#include "model/PortInfo.h" + +namespace DSENT +{ + PortInfo::PortInfo(const String& port_name_, const NetIndex& net_index_) + : m_port_name_(port_name_), m_net_index_(net_index_), m_tran_info_(TransitionInfo()) + { + } + + PortInfo::~PortInfo() + { + } + + const String& PortInfo::getPortName() const + { + return m_port_name_; + } + + const NetIndex& PortInfo::getNetIndex() const + { + return m_net_index_; + } + + void PortInfo::setTransitionInfo(const TransitionInfo& trans_info_) + { + m_tran_info_ = trans_info_; + return; + } + + const TransitionInfo& PortInfo::getTransitionInfo() const + { + return m_tran_info_; + } +} // namespace DSENT + diff --git a/ext/dsent/model/PortInfo.h b/ext/dsent/model/PortInfo.h new file mode 100644 index 000000000..68cd5dc19 --- /dev/null +++ b/ext/dsent/model/PortInfo.h @@ -0,0 +1,37 @@ +#ifndef __DSENT_MODEL_PORT_INFO_H__ +#define __DSENT_MODEL_PORT_INFO_H__ + +#include "util/CommonType.h" +#include "model/ElectricalModel.h" +#include "model/TransitionInfo.h" + +namespace DSENT +{ + class PortInfo + { + public: + PortInfo(const String& port_name_, const NetIndex& net_index_ = NetIndex(0, 0)); + ~PortInfo(); + + public: + // Get the port name + const String& getPortName() const; + // Get the net index + const NetIndex& getNetIndex() const; + // Set the transition information of this port + void setTransitionInfo(const TransitionInfo& trans_info_); + // Get the transition information of this port + const TransitionInfo& getTransitionInfo() const; + + private: + // Name of this port + String m_port_name_; + // Net index of the input port + NetIndex m_net_index_; + // Store the transition information of this port + TransitionInfo m_tran_info_; + }; // class PortInfo +} // namespace DSENT + +#endif // __DSENT_MODEL_PORT_INFO_H__ + diff --git a/ext/dsent/model/TransitionInfo.cc b/ext/dsent/model/TransitionInfo.cc new file mode 100644 index 000000000..ac4402060 --- /dev/null +++ b/ext/dsent/model/TransitionInfo.cc @@ -0,0 +1,70 @@ +#include "model/TransitionInfo.h" + +namespace DSENT +{ + TransitionInfo::TransitionInfo() + : m_number_transitions_00_(0.25), m_number_transitions_01_(0.25), + m_number_transitions_11_(0.25), m_frequency_multiplier_(1.0) + { + update(); + } + + TransitionInfo::TransitionInfo(double number_transitions_00_, double number_transitions_01_, + double number_transitions_11_) + : m_number_transitions_00_(number_transitions_00_), m_number_transitions_01_(number_transitions_01_), + m_number_transitions_11_(number_transitions_11_) + { + m_frequency_multiplier_ = m_number_transitions_00_ + 2.0 * m_number_transitions_01_ + m_number_transitions_11_; + update(); + } + + TransitionInfo::~TransitionInfo() + {} + + void TransitionInfo::update() + { + ASSERT(m_number_transitions_00_ >= 0.0, "[Error] Number of 0->0 transitions (" + + (String)m_number_transitions_00_ + ") must be >= 0.0!"); + ASSERT(m_number_transitions_01_ >= 0.0, "[Error] Number of 0->1 transitions (" + + (String)m_number_transitions_01_ + ") must be >= 0.0!"); + ASSERT(m_number_transitions_11_ >= 0.0, "[Error] Number of 1->1 transitions (" + (String)m_number_transitions_11_ + ") must be >= 0.0!"); + + m_probability_1_ = (m_number_transitions_01_ + m_number_transitions_11_) / m_frequency_multiplier_; + m_probability_0_ = 1.0 - m_probability_1_; + return; + } + + TransitionInfo TransitionInfo::scaleFrequencyMultiplier(double frequency_multiplier_) const + { + // A short cut if frequency_multiplier_ == m_frequency_multiplier_ to avoid excess calculations + if(frequency_multiplier_ == m_frequency_multiplier_) + { + return TransitionInfo(m_number_transitions_00_, m_number_transitions_01_, m_number_transitions_11_); + } + else if (frequency_multiplier_ > m_frequency_multiplier_) + { + double freq_ratio = frequency_multiplier_ / m_frequency_multiplier_; + double diff_num_trans_01 = m_number_transitions_01_ * (freq_ratio - 1.0); + double norm_num_trans_00 = m_number_transitions_00_ * freq_ratio + diff_num_trans_01; + double norm_num_trans_01 = m_number_transitions_01_; + double norm_num_trans_11 = m_number_transitions_11_ * freq_ratio + diff_num_trans_01; + + return TransitionInfo(norm_num_trans_00, norm_num_trans_01, norm_num_trans_11); + } + else + { + ASSERT(false, "[Error] Cannot scale to frequency multiplier (" + (String) frequency_multiplier_ + + ") since current frequency multiplier (" + (String) m_frequency_multiplier_ + ") is bigger!"); + } + } + + void TransitionInfo::print(std::ostream& ost_) const + { + ost_ << "[" << m_number_transitions_00_ << ", " << m_number_transitions_01_ << ", " << m_number_transitions_11_ << "]"; + ost_ << " [" << m_number_transitions_00_ / m_frequency_multiplier_; + ost_ << ", " << m_number_transitions_01_*2.0 / m_frequency_multiplier_; + ost_ << ", " << m_number_transitions_11_ / m_frequency_multiplier_ << "]" << endl; + return; + } +} // namespace DSENT + diff --git a/ext/dsent/model/TransitionInfo.h b/ext/dsent/model/TransitionInfo.h new file mode 100644 index 000000000..6f00cb86a --- /dev/null +++ b/ext/dsent/model/TransitionInfo.h @@ -0,0 +1,50 @@ +#ifndef __DSENT_MODEL_TRANSITION_INFO_H__ +#define __DSENT_MODEL_TRANSITION_INFO_H__ + +#include "util/CommonType.h" + +namespace DSENT +{ + /** + * \brief This class contains the number of transitions and the frequency multiplier information + */ + class TransitionInfo + { + public: + TransitionInfo(); + TransitionInfo(double number_transitions_00_, double number_transitions_01_, double number_transitions_11_); + ~TransitionInfo(); + + public: + inline double getNumberTransitions00() const { return m_number_transitions_00_; } + inline double getNumberTransitions01() const { return m_number_transitions_01_; } + inline double getNumberTransitions11() const { return m_number_transitions_11_; } + inline double getFrequencyMultiplier() const { return m_frequency_multiplier_; } + inline double getProbability0() const { return m_probability_1_; } + inline double getProbability1() const { return m_probability_1_; } + + inline void setNumberTransitions00(double value_) { m_number_transitions_00_ = value_; } + inline void setNumberTransitions01(double value_) { m_number_transitions_01_ = value_; } + inline void setNumberTransitions11(double value_) { m_number_transitions_11_ = value_; } + inline void setFrequencyMultiplier(double value_) { m_frequency_multiplier_ = value_; } + + void update(); + TransitionInfo scaleFrequencyMultiplier(double frequency_multiplier_) const; + + void print(std::ostream& ost_) const; + + private: + // m_number_transitions_xy_ defines number of transitions from x to y + double m_number_transitions_00_; + double m_number_transitions_01_; + double m_number_transitions_11_; + // The multiplier that defines the ratio of the transition frequency and the main core clock frequency + double m_frequency_multiplier_; + // Probability of being at state 0/1 + double m_probability_0_; + double m_probability_1_; + }; // class TransitionInfo +} // namespace DSENT + +#endif // __DSENT_MODEL_TRANSITION_INFO_H__ + diff --git a/ext/dsent/model/electrical/BarrelShifter.cc b/ext/dsent/model/electrical/BarrelShifter.cc new file mode 100644 index 000000000..b951fc566 --- /dev/null +++ b/ext/dsent/model/electrical/BarrelShifter.cc @@ -0,0 +1,241 @@ +#include "model/electrical/BarrelShifter.h" +#include "model/electrical/Multiplexer.h" + +#include <cmath> + +#include "model/PortInfo.h" +#include "model/TransitionInfo.h" +#include "model/EventInfo.h" +#include "model/timing_graph/ElectricalDriverMultiplier.h" +#include "model/timing_graph/ElectricalNet.h" +#include "model/std_cells/StdCell.h" +#include "model/std_cells/StdCellLib.h" + +namespace DSENT +{ + BarrelShifter::BarrelShifter(const String& instance_name_, const TechModel* tech_model_) + : ElectricalModel(instance_name_, tech_model_) + { + initParameters(); + initProperties(); + } + + BarrelShifter::~BarrelShifter() + {} + + void BarrelShifter::initParameters() + { + addParameterName("NumberBits"); + addParameterName("ShiftIndexMin"); + addParameterName("ShiftIndexMax"); + addParameterName("BitDuplicate", "TRUE"); + return; + } + + void BarrelShifter::initProperties() + { + return; + } + + BarrelShifter* BarrelShifter::clone() const + { + return NULL; + } + + void BarrelShifter::constructModel() + { + // Get parameters + unsigned int number_bits = getParameter("NumberBits"); + unsigned int number_shift_bits = (unsigned int)ceil(log2((double) number_bits)); + unsigned int shift_index_min = getParameter("ShiftIndexMin"); + unsigned int shift_index_max = getParameter("ShiftIndexMax"); + bool bit_duplicate = (bool) getParameter("BitDuplicate"); + + ASSERT(number_bits > 0, "[Error] " + getInstanceName() + " -> Number of bits must be > 0!"); + // No need to check these if there arent any shifts + if (number_shift_bits > 0) + { + ASSERT(shift_index_min <= number_shift_bits, + "[Error] " + getInstanceName() + " -> Min shift index must be >= 0 and <= " + + "the total number of shift bits!"); + ASSERT(shift_index_max >= shift_index_min && shift_index_max <= number_shift_bits, + "[Error] " + getInstanceName() + " -> Max shift index must be >= minimum shift index and <= " + + "the total number of shift bits!"); + } + + //Construct electrical ports + //Create each input port + createInputPort( "In", makeNetIndex(0, number_bits-1)); + //Create output + createOutputPort( "Out", makeNetIndex(0, number_bits-1)); + + //Create shift ports (which only exists if there is something to shift) + if (shift_index_min != number_shift_bits) + for (unsigned int i = shift_index_min; i <= shift_index_max; ++i) + createInputPort( "Shift" + (String) i); + + //Create energy, power, and area results + createElectricalResults(); + createElectricalEventResult("BarrelShift"); + //Set conditions during idle event + getEventInfo("Idle")->setStaticTransitionInfos(); + + //If the input is only 1-bit, connect input to output and be done + if (number_shift_bits == 0 || (shift_index_min == number_shift_bits)) + assign("Out", "In"); + else + { + for (unsigned int i = shift_index_min; i <= shift_index_max; ++i) + { + //Create internally buffered shift select signals + createNet("Shift_b" + (String) i); + createNet("Shift_i" + (String) i); + } + + // Create shift and shifted signals + for (unsigned int i = shift_index_min; i <= shift_index_max; ++i) + { + unsigned int current_shifts = (unsigned int)pow(2, i); + const String& n = (String) current_shifts; + //Instantiate and connect intermediate nets. In a barrel-shifter, the nets do + //all the "shifting" and the muxes just select which to take + createNet("R_" + n, makeNetIndex(0, number_bits-1)); //wire R_n[number_bits-1:0] + createNet("RS_" + n, makeNetIndex(0, number_bits-1)); //wire RS_n[number_bits-1:0] + + //Implements the shifts + //assign RS_n[number_bits-1:number_bits-current_shifts] = R_n[current_shifts-1:0]; + assign("RS_" + n, makeNetIndex(number_bits-current_shifts, number_bits-1), + "R_" + n, makeNetIndex(0, current_shifts-1)); + //assign RS_n[number_bits-current_shifts-1:0] = R_n[current_shifts:number_bits-1]; + assign("RS_" + n, makeNetIndex(0, number_bits-current_shifts-1), + "R_" + n, makeNetIndex(current_shifts, number_bits-1)); + } + + const String& n_max = (String) pow(2, shift_index_max+1); + const String& n_min = (String) pow(2, shift_index_min); + // Create the R_(max) net + createNet("R_" + n_max, makeNetIndex(0, number_bits-1)); + // Set R_1 to be the input + assign("R_" + n_min, "In"); + // Set R_(max) to be the output + assign("Out", "R_" + n_max, makeNetIndex(0, number_bits-1)); + + for (unsigned int i = shift_index_min; i <= shift_index_max; ++i) + { + unsigned int current_shifts = (unsigned int)pow(2, i); + const String& n = (String) current_shifts; + const String& n_next = (String) (current_shifts * 2); + + const String& buf_inv_0_name = "ShiftBufInv0_" + (String) n; + const String& buf_inv_1_name = "ShiftBufInv1_" + (String) n; + // Create shift buffer inverters + StdCell* buf_inv_0 = getTechModel()->getStdCellLib()->createStdCell("INV", buf_inv_0_name); + buf_inv_0->construct(); + StdCell* buf_inv_1 = getTechModel()->getStdCellLib()->createStdCell("INV", buf_inv_1_name); + buf_inv_1->construct(); + + // Connect up shift buffer inverters + portConnect(buf_inv_0, "A", "Shift" + (String) i); + portConnect(buf_inv_0, "Y", "Shift_b" + (String) i); + portConnect(buf_inv_1, "A", "Shift_b" + (String) i); + portConnect(buf_inv_1, "Y", "Shift_i" + (String) i); + + // Add area, power, and event results for inverters + addSubInstances(buf_inv_0, 1.0); + addSubInstances(buf_inv_1, 1.0); + addElectricalSubResults(buf_inv_0, 1.0); + addElectricalSubResults(buf_inv_1, 1.0); + getEventResult("BarrelShift")->addSubResult(buf_inv_0->getEventResult("INV"), buf_inv_0_name, 1.0); + getEventResult("BarrelShift")->addSubResult(buf_inv_1->getEventResult("INV"), buf_inv_1_name, 1.0); + + //Instantiate 2:1 multiplexers, one for each shift bit. + const String& mux_name = "SRL" + n; + Multiplexer* mux = new Multiplexer(mux_name, getTechModel()); + mux->setParameter("NumberInputs", 2); + mux->setParameter("NumberBits", number_bits); + mux->setParameter("BitDuplicate", bit_duplicate); + mux->construct(); + + //Just have to connect the In0 and In1 inputs of the mux to the + //non-shifted and shifted intermediate signals, respectively. + portConnect(mux, "In0", "R_" + n); + portConnect(mux, "In1", "RS_" + n); + //Selector connects to the shift signal for that index + portConnect(mux, "Sel0", "Shift_i" + (String) i); + //Connect mux output + portConnect(mux, "Out", "R_" + n_next); + + //Add area, power, and event results for each mux + addSubInstances(mux, 1.0); + addElectricalSubResults(mux, 1.0); + getEventResult("BarrelShift")->addSubResult(mux->getEventResult("Mux"), mux_name, 1.0); + } + } + return; + } + + void BarrelShifter::propagateTransitionInfo() + { + // The only thing can be updated are the input probabilities...so we will update them + unsigned int number_bits = (unsigned int) getParameter("NumberBits"); + unsigned int number_shift_bits = (unsigned int) ceil(log2((double) number_bits)); + unsigned int shift_index_min = getParameter("ShiftIndexMin"); + unsigned int shift_index_max = getParameter("ShiftIndexMax"); + + // Keep track of the multiplexer of the last stage + ElectricalModel* last_mux = NULL; + // We only need to update stuff if we are not shifting by exact multiples + // of number of input bits + if (shift_index_min < number_shift_bits) + { + for (unsigned int i = shift_index_min; i <= shift_index_max; ++i) + { + unsigned int current_shifts = (unsigned int)pow(2, i); + String n = (String) current_shifts; + + // Set the + const String& buf_inv_0_name = "ShiftBufInv0_" + (String) n; + const String& buf_inv_1_name = "ShiftBufInv1_" + (String) n; + const String& mux_name = "SRL" + n; + + // Set the transition infos for the inverter buffers + ElectricalModel* buf_inv_0 = (ElectricalModel*) getSubInstance(buf_inv_0_name); + propagatePortTransitionInfo(buf_inv_0, "A", "Shift" + (String) i); + buf_inv_0->use(); + + ElectricalModel* buf_inv_1 = (ElectricalModel*) getSubInstance(buf_inv_1_name); + propagatePortTransitionInfo(buf_inv_1, "A", buf_inv_0, "Y"); + buf_inv_1->use(); + + // Set the transition infos for the shift multiplexers + ElectricalModel* mux = (ElectricalModel*) getSubInstance(mux_name); + propagatePortTransitionInfo(mux, "Sel0", buf_inv_1, "Y"); + if (last_mux == NULL) + { + propagatePortTransitionInfo(mux, "In0", "In"); + propagatePortTransitionInfo(mux, "In1", "In"); + } + else + { + propagatePortTransitionInfo(mux, "In0", last_mux, "Out"); + propagatePortTransitionInfo(mux, "In1", last_mux, "Out"); + } + mux->use(); + + // Set this to be the last mux visted + last_mux = mux; + } + } + + // If there isn't anything to shift + if (last_mux == NULL) + propagatePortTransitionInfo("Out", "In"); + // Take the transition info of the last mux + else + propagatePortTransitionInfo("Out", last_mux, "Out"); + + return; + } + +} // namespace DSENT + diff --git a/ext/dsent/model/electrical/BarrelShifter.h b/ext/dsent/model/electrical/BarrelShifter.h new file mode 100644 index 000000000..e26ca9e91 --- /dev/null +++ b/ext/dsent/model/electrical/BarrelShifter.h @@ -0,0 +1,34 @@ +#ifndef __DSENT_MODEL_ELECTRICAL_BARRELSHIFTER_H__ +#define __DSENT_MODEL_ELECTRICAL_BARRELSHIFTER_H__ + +#include "util/CommonType.h" +#include "model/ElectricalModel.h" + +namespace DSENT +{ + // A model on N-bit barrel-shifter. Shifts to the right by X + class BarrelShifter : public ElectricalModel + { + public: + BarrelShifter(const String& instance_name_, const TechModel* tech_model_); + virtual ~BarrelShifter(); + + public: + // Set a list of properties' name needed to construct model + void initParameters(); + // Set a list of properties' name needed to construct model + void initProperties(); + + // Clone and return a new instance + virtual BarrelShifter* clone() const; + + protected: + // Build the model + virtual void constructModel(); + virtual void propagateTransitionInfo(); + + }; // class BarrelShifter +} // namespace DSENT + +#endif // __DSENT_MODEL_ELECTRICAL_MULTIPLEXER_H__ + diff --git a/ext/dsent/model/electrical/BroadcastHTree.cc b/ext/dsent/model/electrical/BroadcastHTree.cc new file mode 100644 index 000000000..efac128e7 --- /dev/null +++ b/ext/dsent/model/electrical/BroadcastHTree.cc @@ -0,0 +1,400 @@ +#include "model/electrical/BroadcastHTree.h" + +#include <cmath> +#include <vector> + +#include "model/PortInfo.h" +#include "model/EventInfo.h" +#include "model/TransitionInfo.h" +#include "model/std_cells/StdCellLib.h" +#include "model/std_cells/StdCell.h" +#include "model/timing_graph/ElectricalLoad.h" +#include "model/timing_graph/ElectricalDelay.h" +#include "model/timing_graph/ElectricalDriver.h" +#include "model/timing_graph/ElectricalTimingTree.h" +#include "model/timing_graph/ElectricalNet.h" + +namespace DSENT +{ + using std::pow; + using std::vector; + + BroadcastHTree::BroadcastHTree(const String& instance_name_, const TechModel* tech_model_) + : ElectricalModel(instance_name_, tech_model_) + { + initParameters(); + initProperties(); + + m_leaf_load_ = NULL; + m_leaf_head_driver_ = NULL; + m_leaf_head_load_ = NULL; + } + + BroadcastHTree::~BroadcastHTree() + { + clearPtrVector<StdCell>(&m_repeaters_); + clearPtrVector<ElectricalLoad>(&m_repeater_loads_); + clearPtrVector<ElectricalTimingTree>(&m_timing_trees_); + clearPtrVector<StdCell>(&m_leaf_drivers_); + delete m_leaf_load_; + delete m_leaf_head_driver_; + delete m_leaf_head_load_; + } + + void BroadcastHTree::initParameters() + { + addParameterName("NumberLevels"); + addParameterName("NumberBits"); + addParameterName("WireLayer"); + addParameterName("WireWidthMultiplier", 1.0); + addParameterName("WireSpacingMultiplier", 1.0); + return; + } + + void BroadcastHTree::initProperties() + { + addPropertyName("SitePitch"); + addPropertyName("TotalLoadCapPerBit"); + return; + } + + BroadcastHTree* BroadcastHTree::clone() const + { + // TODO + return NULL; + } + + void BroadcastHTree::constructModel() + { + // Get parameters + unsigned int number_levels = getParameter("NumberLevels").toUInt(); + unsigned int number_bits = getParameter("NumberBits").toUInt(); + const String& wire_layer = getParameter("WireLayer"); + double wire_width_multiplier = getParameter("WireWidthMultiplier").toDouble(); + double wire_spacing_multiplier = getParameter("WireSpacingMultiplier").toDouble(); + + ASSERT(number_levels > 0, "[Error] " + getInstanceName() + + " -> Number of levels must be > 0!"); + ASSERT(number_bits > 0, "[Error] " + getInstanceName() + + " -> Number of bits must be > 0!"); + ASSERT(getTechModel()->isWireLayerExist(wire_layer), "[Error] " + getInstanceName() + + " -> Wire layer does not exist!"); + ASSERT(wire_width_multiplier >= 1.0, "[Error] " + getInstanceName() + + " -> Wire width multiplier must be >= 1.0!"); + ASSERT(wire_spacing_multiplier >= 1.0, "[Error] " + getInstanceName() + + " -> Wire spacing multiplier must be >= 1.0!"); + + double wire_min_width = getTechModel()->get("Wire->" + wire_layer + "->MinWidth").toDouble(); + double wire_min_spacing = getTechModel()->get("Wire->" + wire_layer + "->MinSpacing").toDouble(); + + double wire_width = wire_min_width * wire_width_multiplier; + double wire_spacing = wire_min_spacing * wire_spacing_multiplier; + + double wire_cap_per_len = getTechModel()->calculateWireCapacitance(wire_layer, wire_width, wire_spacing, 1.0); + double wire_res_per_len = getTechModel()->calculateWireResistance(wire_layer, wire_width, 1.0); + + getGenProperties()->set("WireWidth", wire_width); + getGenProperties()->set("WireSpacing", wire_spacing); + getGenProperties()->set("WireCapacitancePerLength", wire_cap_per_len); + getGenProperties()->set("WireResistancePerLength", wire_res_per_len); + + // Create ports + createInputPort("In", makeNetIndex(0, number_bits-1)); + createOutputPort("Out", makeNetIndex(0, number_bits-1)); + + // Create connections + createNet("InTmp"); + createNet("OutTmp"); + assignVirtualFanin("InTmp", "In"); + assignVirtualFanout("Out", "OutTmp"); + + createLoad("In_Cap"); + createDelay("In_to_Out_delay"); + + ElectricalLoad* in_cap = getLoad("In_Cap"); + ElectricalDelay* in_to_out_delay = getDelay("In_to_Out_delay"); + + getNet("InTmp")->addDownstreamNode(in_cap); + in_cap->addDownstreamNode(in_to_out_delay); + + // Init + for(unsigned int i = 0; i < number_levels; ++i) + { + StdCell* repeater = getTechModel()->getStdCellLib()->createStdCell("INV", "Repeater" + (String)i); + ElectricalLoad* repeater_load = new ElectricalLoad("RepeaterIn_Cap" + (String)i, this); + ElectricalTimingTree* timing_tree = new ElectricalTimingTree("RepeatedLink" + (String)i, this); + + repeater->construct(); + repeater->getNet("Y")->addDownstreamNode(repeater_load); + m_repeaters_.push_back(repeater); + m_repeater_loads_.push_back(repeater_load); + m_timing_trees_.push_back(timing_tree); + } + + // Create area, power, and event results + createElectricalAtomicResults(); + createElectricalEventResult("Send"); + addEventResult(new AtomicResult("DriveLoad")); + addEventResult(new AtomicResult("DriveTree")); + + getEventResult("Send")->addSubResult(getEventResult("DriveLoad"), "Self", 1.0); + getEventResult("Send")->addSubResult(getEventResult("DriveTree"), "Self", 1.0); + return; + } + + void BroadcastHTree::updateModel() + { + // Get properties + double site_pitch = getProperty("SitePitch").toDouble(); + double total_load_cap_per_bit = getProperty("TotalLoadCapPerBit").toDouble(); + + ASSERT(site_pitch > 0, "[Error] " + getInstanceName() + + " -> Site pitch must be > 0!"); + ASSERT(total_load_cap_per_bit >= 0.0, "[Error] " + getInstanceName() + + " -> Total load capacitance per bit must be >= 0!"); + + // Get parameters + unsigned int number_levels = getParameter("NumberLevels"); + unsigned int number_bits = getParameter("NumberBits"); + + const String& wire_layer = getParameter("WireLayer"); + double wire_width = getGenProperties()->get("WireWidth").toDouble(); + double wire_spacing = getGenProperties()->get("WireSpacing").toDouble(); + double wire_cap_per_len = getGenProperties()->get("WireCapacitancePerLength").toDouble(); + double wire_res_per_len = getGenProperties()->get("WireResistancePerLength").toDouble(); + + double leaf_load_cap = total_load_cap_per_bit / pow(2.0, (double)(number_levels-1)); + + vector<double> wire_caps(number_levels, 0.0); + vector<double> wire_ress(number_levels, 0.0); + double wire_length = site_pitch / 2.0; + for(unsigned int i = 0; i < number_levels; ++i) + { + wire_caps[i] = wire_cap_per_len * wire_length; + wire_ress[i] = wire_res_per_len * wire_length; + wire_length /= 2.0; + } + + // Start sizing each stage of repeaters for a transition times. TODO: Find a heuristic about + // how the transition time is done...place and route tools make this user-specified + double required_transition = 40e-12; + m_number_segments_.resize(number_levels, 1); + for(unsigned int i = 0; i < number_levels; ++i) + { + Log::printLine(getInstanceName() + " -> Beginning Repeater Insertion " + (String)i); + + double transition; + unsigned int iteration = 0; + m_repeaters_[i]->setMinDrivingStrength(); + m_repeaters_[i]->getNet("Y")->setDistributedCap(wire_caps[i] / m_number_segments_[i]); + m_repeaters_[i]->getNet("Y")->setDistributedRes(wire_ress[i] / m_number_segments_[i]); + m_repeater_loads_[i]->setLoadCap(m_repeaters_[i]->getNet("A")->getTotalDownstreamCap()); + + transition = m_timing_trees_[i]->calculateNodeTransition(m_repeaters_[i]->getNet("Y")); + + while(required_transition < transition) + { + Log::printLine(getInstanceName() + " -> Repeater Insertion Iteration " + (String)iteration + + ": Required transition = " + (String)required_transition + + ", Transition = " + (String)transition + + ", Slack = " + (String)(required_transition - transition) + + ", Number of repeaters = " + (String)m_number_segments_[i]); + + // Size up if transition is not met + while(required_transition < transition) + { + if(m_repeaters_[i]->hasMaxDrivingStrength()) + { + break; + } + m_repeaters_[i]->increaseDrivingStrength(); + m_repeater_loads_[i]->setLoadCap(m_repeaters_[i]->getNet("A")->getTotalDownstreamCap()); + transition = m_timing_trees_[i]->calculateNodeTransition(m_repeaters_[i]->getNet("Y")); + + iteration++; + Log::printLine(getInstanceName() + " -> Slack: " + (String)(required_transition - transition)); + } + // Increase number of segments if thansition is not met + if(required_transition < transition) + { + m_number_segments_[i]++; + m_repeaters_[i]->setMinDrivingStrength(); + m_repeaters_[i]->getNet("Y")->setDistributedCap(wire_caps[i] / m_number_segments_[i]); + m_repeaters_[i]->getNet("Y")->setDistributedRes(wire_ress[i] / m_number_segments_[i]); + m_repeater_loads_[i]->setLoadCap(m_repeaters_[i]->getNet("A")->getTotalDownstreamCap()); + transition = m_timing_trees_[i]->calculateNodeTransition(m_repeaters_[i]->getNet("Y")); + } + } + Log::printLine(getInstanceName() + " -> Repeater Insertion " + (String)i + " Ended after Iteration: " + (String)iteration + + ": Required transition = " + (String)required_transition + + ", Transition = " + (String)transition + + ", Slack = " + (String)(required_transition - transition) + + ", Number of repeaters = " + (String)m_number_segments_[i]); + } + + // Insert inverters to ensure the transition time at the leaf + int min_driving_strength_idx = m_repeaters_[number_levels-1]->getDrivingStrengthIdx(); + + // Remove everything and rebuild again + clearPtrVector<StdCell>(&m_leaf_drivers_); + delete m_leaf_load_; + delete m_leaf_head_driver_; + delete m_leaf_head_load_; + + m_leaf_head_driver_ = getTechModel()->getStdCellLib()->createStdCell("INV", "LeafHeadDriver"); + m_leaf_head_driver_->construct(); + m_leaf_head_driver_->setDrivingStrengthIdx(min_driving_strength_idx); + + m_leaf_head_load_ = new ElectricalLoad("LeafHead_Cap", this); + m_leaf_head_driver_->getNet("Y")->addDownstreamNode(m_leaf_head_load_); + + m_leaf_load_ = new ElectricalLoad("Leaf_Cap", this); + m_leaf_load_->setLoadCap(leaf_load_cap); + + StdCell* inv = getTechModel()->getStdCellLib()->createStdCell("INV", "LeafDriver0"); + inv->construct(); + inv->getNet("Y")->addDownstreamNode(m_leaf_load_); + inv->setDrivingStrengthIdx(min_driving_strength_idx); + m_leaf_drivers_.push_back(inv); + + m_leaf_head_load_->setLoadCap(m_leaf_drivers_[0]->getNet("A")->getTotalDownstreamCap()); + + // Start inserting the buffers + ElectricalTimingTree t2("LeafHead", m_leaf_head_driver_); + int curr_driver = 0; + unsigned int iteration = 0; + while(true) + { + ElectricalTimingTree t("LeafDriver", m_leaf_drivers_[curr_driver]); + double transition = t.calculateNodeTransition(m_leaf_drivers_[curr_driver]->getNet("Y")); + Log::printLine(getInstanceName() + " -> Buffer Insertion : " + (String)iteration + + ": Required transition = " + (String)required_transition + + ", Transition = " + (String)transition + + ", Slack = " + (String)(required_transition - transition) + + ", Number of buffers = " + (String)(curr_driver+1)); + + // Size up the inverter at curr_driver so that it could drive the next stage + while(required_transition < transition) + { + if(m_leaf_drivers_[curr_driver]->hasMaxDrivingStrength()) + { + const String& warning_msg = "[Warning] " + getInstanceName() + " -> Transition not met" + + ": Required transition = " + (String)required_transition + + ", Transition = " + (String)transition + + ", Slack = " + (String)(required_transition - transition); + Log::printLine(std::cerr, warning_msg); + break; + } + m_leaf_drivers_[curr_driver]->increaseDrivingStrength(); + transition = t.calculateNodeTransition(m_leaf_drivers_[curr_driver]->getNet("Y")); + iteration++; + } + // Add an additional inverter if the transition for the first stage does not meet the required transition + m_leaf_head_load_->setLoadCap(m_leaf_drivers_[curr_driver]->getNet("A")->getTotalDownstreamCap()); + transition = t2.calculateNodeTransition(m_leaf_head_driver_->getNet("Y")); + if(required_transition < transition) + { + inv = getTechModel()->getStdCellLib()->createStdCell("INV", "LeafDriver" + (String)(curr_driver+1)); + inv->construct(); + inv->getNet("Y")->addDownstreamNode(m_leaf_drivers_[curr_driver]->getNet("A")); + inv->setDrivingStrengthIdx(min_driving_strength_idx); + m_leaf_drivers_.push_back(inv); + curr_driver++; + } + else + { + Log::printLine(getInstanceName() + " -> Buffer Insertion Ended after Iteration: " + (String)iteration + + ", Number of buffers = " + (String)(curr_driver+1)); + break; + } + } + + + // Update electrical interfaces + getLoad("In_Cap")->setLoadCap(m_repeaters_[0]->getNet("A")->getTotalDownstreamCap()); + // TODO + getDelay("In_to_Out_delay")->setDelay(0.0); + + // Reset all the atomic results to 0 before start updating new results + resetElectricalAtomicResults(); + + // Update area, power results + double wire_area = 0.0; + wire_length = site_pitch / 2.0; + unsigned int number_branches = 1; + for(unsigned int i = 0; i < number_levels; ++i) + { + wire_area += wire_length * (wire_width + wire_spacing) * number_branches * number_bits; + addElecticalAtomicResultValues(m_repeaters_[i], m_number_segments_[i] * number_branches * number_bits); + wire_length /= 2.0; + number_branches *= 2; + } + number_branches = (unsigned int)pow(2.0, (double)number_levels-1); + addElecticalAtomicResultValues(m_leaf_head_driver_, number_branches * number_bits); + for(unsigned int i = 0; i < m_leaf_drivers_.size(); ++i) + { + addElecticalAtomicResultValues(m_leaf_drivers_[i], number_branches * number_bits); + } + addElecticalWireAtomicResultValue(wire_layer, wire_area); + + return; + } + + void BroadcastHTree::useModel() + { + unsigned int number_bits = getParameter("NumberBits").toUInt(); + unsigned int number_levels = getParameter("NumberLevels").toUInt(); + + // Update the transition information for the modeled repeaters + // Since we only modeled one repeater. So the transition information for 0->0 and 1->1 + // is averaged out + const TransitionInfo& trans_In = getInputPort("In")->getTransitionInfo(); + double average_static_transition = (trans_In.getNumberTransitions00() + trans_In.getNumberTransitions11()) / 2.0; + TransitionInfo mod_trans_In(average_static_transition, trans_In.getNumberTransitions01(), average_static_transition); + + // Propagate the transition information + propagateTransitionInfo(); + + // Update leakage and event + double energy = 0.0; + double power = 0.0; + unsigned int number_branches = 1; + for(unsigned int i = 0; i < number_levels; ++i) + { + assignPortTransitionInfo(m_repeaters_[i], "A", mod_trans_In); + m_repeaters_[i]->use(); + power += m_repeaters_[i]->getNddPowerResult("Leakage")->calculateSum() * m_number_segments_[i] * number_branches; + energy += m_repeaters_[i]->getEventResult("INV")->calculateSum() * m_number_segments_[i] * number_branches; + number_branches *= 2; + } + energy *= number_bits; + getEventResult("DriveTree")->setValue(energy); + + energy = 0.0; + assignPortTransitionInfo(m_leaf_head_driver_, "A", mod_trans_In); + m_leaf_head_driver_->use(); + number_branches = (unsigned int)pow(2.0, (double)number_levels-1); + power += m_leaf_head_driver_->getNddPowerResult("Leakage")->calculateSum() * number_branches; + energy += m_leaf_head_driver_->getEventResult("INV")->calculateSum() * number_branches; + for(unsigned int i = 0; i < m_leaf_drivers_.size(); ++i) + { + assignPortTransitionInfo(m_leaf_drivers_[i], "A", mod_trans_In); + m_leaf_drivers_[i]->use(); + power += m_leaf_drivers_[i]->getNddPowerResult("Leakage")->calculateSum() * number_branches; + energy += m_leaf_drivers_[i]->getEventResult("INV")->calculateSum() * number_branches; + } + power *= number_bits; + energy *= number_bits; + getEventResult("DriveLoad")->setValue(energy); + getNddPowerResult("Leakage")->setValue(power); + + return; + } + + void BroadcastHTree::propagateTransitionInfo() + { + propagatePortTransitionInfo("Out", "In"); + return; + } +} // namespace DSENT + diff --git a/ext/dsent/model/electrical/BroadcastHTree.h b/ext/dsent/model/electrical/BroadcastHTree.h new file mode 100644 index 000000000..f2c8d407b --- /dev/null +++ b/ext/dsent/model/electrical/BroadcastHTree.h @@ -0,0 +1,54 @@ +#ifndef __DSENT_MODEL_ELECTRICAL_BROADCAST_HTREE_H__ +#define __DSENT_MODEL_ELECTRICAL_BROADCAST_HTREE_H__ + +#include "util/CommonType.h" +#include "model/ElectricalModel.h" + +#include <vector> + +namespace DSENT +{ + using std::vector; + + class StdCell; + class ElectricalLoad; + class ElectricalTimingTree; + + class BroadcastHTree : public ElectricalModel + { + public: + BroadcastHTree(const String& instance_name_, const TechModel* tech_model_); + virtual ~BroadcastHTree(); + + public: + // Set a list of properties' name needed to construct model + void initParameters(); + // Set a list of properties' name needed to construct model + void initProperties(); + + // Clone and return a new instance + virtual BroadcastHTree* clone() const; + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void useModel(); + virtual void propagateTransitionInfo(); + + private: + vector<StdCell*> m_repeaters_; + vector<ElectricalLoad*> m_repeater_loads_; + vector<ElectricalTimingTree*> m_timing_trees_; + vector<unsigned int> m_number_segments_; + + vector<StdCell*> m_leaf_drivers_; + ElectricalLoad* m_leaf_load_; + StdCell* m_leaf_head_driver_; + ElectricalLoad* m_leaf_head_load_; + + }; // class BroadcastHTree +} // namespace DSENT + +#endif // __DSENT_MODEL_ELECTRICAL_BROADCAST_HTREE_H__ + diff --git a/ext/dsent/model/electrical/DFFRAM.cc b/ext/dsent/model/electrical/DFFRAM.cc new file mode 100644 index 000000000..604aead2f --- /dev/null +++ b/ext/dsent/model/electrical/DFFRAM.cc @@ -0,0 +1,321 @@ +#include "model/electrical/DFFRAM.h" + +#include <cmath> + +#include "model/PortInfo.h" +#include "model/EventInfo.h" +#include "model/TransitionInfo.h" +#include "model/timing_graph/ElectricalDriverMultiplier.h" +#include "model/timing_graph/ElectricalNet.h" +#include "model/std_cells/StdCell.h" +#include "model/std_cells/StdCellLib.h" +#include "model/electrical/Decoder.h" +#include "model/electrical/Multiplexer.h" + +namespace DSENT +{ + using std::ceil; + + DFFRAM::DFFRAM(const String& instance_name_, const TechModel* tech_model_) + : ElectricalModel(instance_name_, tech_model_) + { + initParameters(); + initProperties(); + } + + DFFRAM::~DFFRAM() + {} + + void DFFRAM::initParameters() + { + addParameterName("NumberEntries"); + addParameterName("NumberBits"); + return; + } + + void DFFRAM::initProperties() + { + return; + } + + DFFRAM* DFFRAM::clone() const + { + // TODO + return NULL; + } + + void DFFRAM::constructModel() + { + // Get parameters + unsigned int number_bits = getParameter("NumberBits").toUInt(); + unsigned int number_entries = getParameter("NumberEntries").toUInt(); + + ASSERT(number_bits > 0, "[Error] " + getInstanceName() + + " -> Number of bits must be > 0!"); + ASSERT(number_entries > 0, "[Error] " + getInstanceName() + + " -> Number of entries must be > 0!"); + + unsigned int number_addr_bits = (unsigned int)ceil(log2(number_entries)); + + // Create ports + createInputPort("In", makeNetIndex(0, number_bits-1)); + for(unsigned int i = 0; i < number_addr_bits; ++i) + { + createInputPort("WRAddr" + (String)i); + createInputPort("RDAddr" + (String)i); + } + createInputPort("WE"); + createInputPort("CK"); + createOutputPort("Out", makeNetIndex(0, number_bits-1)); + + // Create energy, power, and area results + createElectricalResults(); + getEventInfo("Idle")->setStaticTransitionInfos(); + getEventInfo("Idle")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0)); + getEventInfo("Idle")->setTransitionInfo("WE", TransitionInfo(1.0, 0.0, 0.0)); + + createElectricalEventResult("Read"); + getEventInfo("Read")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0)); + getEventInfo("Read")->setTransitionInfo("WE", TransitionInfo(1.0, 0.0, 0.0)); + for(unsigned int i = 0; i < number_addr_bits; ++i) + { + getEventInfo("Read")->setTransitionInfo("WRAddr" + (String)i, TransitionInfo(0.5, 0.0, 0.5)); + } + createElectricalEventResult("Write"); + getEventInfo("Write")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0)); + getEventInfo("Write")->setTransitionInfo("WE", TransitionInfo(0.0, 0.0, 1.0)); + for(unsigned int i = 0; i < number_addr_bits; ++i) + { + getEventInfo("Write")->setTransitionInfo("RDAddr" + (String)i, TransitionInfo(0.5, 0.0, 0.5)); + } + + // Init components - DFF array, Dec, Mux + vector<String> dff_names(number_entries, ""); + vector<StdCell*> dffs(number_entries, NULL); + for(unsigned int i = 0; i < number_entries; ++i) + { + dff_names[i] = "DFF_" + (String)i; + dffs[i] = getTechModel()->getStdCellLib()->createStdCell("DFFQ", dff_names[i]); + dffs[i]->construct(); + } + + const String& dec_name = "Dec"; + Decoder* dec = new Decoder(dec_name, getTechModel()); + dec->setParameter("NumberOutputs", number_entries); + dec->construct(); + + const String& mux_name = "Mux"; + Multiplexer* mux = new Multiplexer(mux_name, getTechModel()); + mux->setParameter("NumberInputs", number_entries); + mux->setParameter("NumberBits", 1); + mux->setParameter("BitDuplicate", "TRUE"); + mux->construct(); + + // Init components - CK & WE + const String& nand2cg0_name = "NAND2_CKGate0"; + StdCell* nand2cg0 = getTechModel()->getStdCellLib()->createStdCell("NAND2", nand2cg0_name); + nand2cg0->construct(); + const String& invcg0_name = "INV_CKGate0"; + StdCell* invcg0 = getTechModel()->getStdCellLib()->createStdCell("INV", invcg0_name); + invcg0->construct(); + + // Init components - (CK & WE) & DecOut[i] + vector<String> nand2cg1_names(number_entries, ""); + vector<StdCell*> nand2cg1s(number_entries, NULL); + vector<String> invcg1_names(number_entries, ""); + vector<StdCell*> invcg1s(number_entries, NULL); + for(unsigned int i = 0; i < number_entries; ++i) + { + nand2cg1_names[i] = "NAND2_CKGate1_" + (String)i; + nand2cg1s[i] = getTechModel()->getStdCellLib()->createStdCell("NAND2", nand2cg1_names[i]); + nand2cg1s[i]->construct(); + + invcg1_names[i] = "INV_CKGate1_" + (String)i; + invcg1s[i] = getTechModel()->getStdCellLib()->createStdCell("INV", invcg1_names[i]); + invcg1s[i]->construct(); + } + + // Connect Decoder + for(unsigned int i = 0; i < number_addr_bits; ++i) + { + portConnect(dec, "Addr" + (String)i, "WRAddr" + (String)i); + } + for(unsigned int i = 0; i < number_entries; ++i) + { + createNet("Dec_Out" + (String)i); + portConnect(dec, "Out" + (String)i, "Dec_Out" + (String)i); + } + + // Connect CKGate0 - CK, WE + createNet("NAND2_CKGate0_Out"); + createNet("CKGate0_Out"); + portConnect(nand2cg0, "A", "CK"); + portConnect(nand2cg0, "B", "WE"); + portConnect(nand2cg0, "Y", "NAND2_CKGate0_Out"); + portConnect(invcg0, "A", "NAND2_CKGate0_Out"); + portConnect(invcg0, "Y", "CKGate0_Out"); + + // Connect CKGate1 - CKGate0, Dec_Out + for(unsigned int i = 0; i < number_entries; ++i) + { + createNet("NAND2_CKGate1_Outs" + (String)i); + createNet("CKGate1_Outs" + (String)i); + portConnect(nand2cg1s[i], "A", "CKGate0_Out"); + portConnect(nand2cg1s[i], "B", "Dec_Out" + (String)i); + portConnect(nand2cg1s[i], "Y", "NAND2_CKGate1_Outs" + (String)i); + portConnect(invcg1s[i], "A", "NAND2_CKGate1_Outs" + (String)i); + portConnect(invcg1s[i], "Y", "CKGate1_Outs" + (String)i); + } + + // Connect DFF array + for(unsigned int i = 0; i < number_entries; ++i) + { + createNet("DFF_Out" + (String)i); + for(unsigned int n = 0; n < number_bits; ++n) + { + portConnect(dffs[i], "D", "In", makeNetIndex(n)); + portConnect(dffs[i], "CK", "CKGate1_Outs" + (String)i); + } + portConnect(dffs[i], "Q", "DFF_Out" + (String)i); + } + + // Connect Multiplexer + createNet("Mux_Out"); + for(unsigned int i = 0; i < number_entries; ++i) + { + portConnect(mux, "In" + (String)i, "DFF_Out" + (String)i); + } + for(unsigned int i = 0; i < number_addr_bits; ++i) + { + portConnect(mux, "Sel" + (String)i, "RDAddr" + (String)i); + } + portConnect(mux, "Out", "Mux_Out"); + + // Use driver multiplier to connect Mux_Out to Out + createDriverMultiplier("OutMult"); + ElectricalDriverMultiplier* drive_mult = getDriverMultiplier("OutMult"); + getNet("Mux_Out")->addDownstreamNode(drive_mult); + for(unsigned int n = 0; n < number_bits; ++n) + { + drive_mult->addDownstreamNode(getNet("Out", makeNetIndex(n))); + } + + // Add area and power results + for(unsigned int i = 0; i < number_entries; ++i) + { + addSubInstances(dffs[i], number_bits); + addElectricalSubResults(dffs[i], number_bits); + } + + addSubInstances(dec, 1.0); + addElectricalSubResults(dec, 1.0); + + addSubInstances(mux, number_bits); + addElectricalSubResults(mux, number_bits); + + addSubInstances(nand2cg0, 1.0); + addElectricalSubResults(nand2cg0, 1.0); + + addSubInstances(invcg0, 1); + addElectricalSubResults(invcg0, 1.0); + + for(unsigned int i = 0; i < number_entries; ++i) + { + addSubInstances(nand2cg1s[i], 1); + addElectricalSubResults(nand2cg1s[i], 1.0); + + addSubInstances(invcg1s[i], 1); + addElectricalSubResults(invcg1s[i], 1.0); + } + + // Add write event + Result* write_event = getEventResult("Write"); + write_event->addSubResult(nand2cg0->getEventResult("NAND2"), nand2cg0_name, 1.0); + write_event->addSubResult(invcg0->getEventResult("INV"), invcg0_name, 1.0); + write_event->addSubResult(dec->getEventResult("Decode"), dec_name, 1.0); + for(unsigned int i = 0; i < number_entries; ++i) + { + write_event->addSubResult(nand2cg1s[i]->getEventResult("NAND2"), nand2cg1_names[i], 1.0); + write_event->addSubResult(invcg1s[i]->getEventResult("INV"), invcg1_names[i], 1.0); + write_event->addSubResult(dffs[i]->getEventResult("DFFD"), dff_names[i], number_bits); + write_event->addSubResult(dffs[i]->getEventResult("DFFQ"), dff_names[i], number_bits); + write_event->addSubResult(dffs[i]->getEventResult("CK"), dff_names[i], number_bits); + } + + // Add read event + Result* read_event = getEventResult("Read"); + //for(unsigned int i = 0; i < number_entries; ++i) + //{ + // read_event->addSubResult(dffs[i]->getEventResult("DFFQ"), dff_names[i], number_bits); + //} + read_event->addSubResult(mux->getEventResult("Mux"), mux_name, number_bits); + + return; + } + + void DFFRAM::propagateTransitionInfo() + { + // Update probability + unsigned int number_entries = (unsigned int)getParameter("NumberEntries"); + unsigned int number_addr_bits = (unsigned int)ceil(log2(number_entries)); + + // Update decoder + ElectricalModel* dec = (ElectricalModel*)getSubInstance("Dec"); + for(unsigned int i = 0; i < number_addr_bits; ++i) + { + propagatePortTransitionInfo(dec, "Addr" + (String)i, "WRAddr" + (String)i); + } + dec->use(); + + // Update CKGate0 nands + invs + ElectricalModel* nand2cg0 = (ElectricalModel*)getSubInstance("NAND2_CKGate0"); + propagatePortTransitionInfo(nand2cg0, "A", "CK"); + propagatePortTransitionInfo(nand2cg0, "B", "WE"); + nand2cg0->use(); + ElectricalModel* invcg0 = (ElectricalModel*)getSubInstance("INV_CKGate0"); + propagatePortTransitionInfo(invcg0, "A", nand2cg0, "Y"); + invcg0->use(); + + // Update CKGate1 nands + invs + vector<ElectricalModel*> nand2cg1s(number_entries, NULL); + vector<ElectricalModel*> invcg1s(number_entries, NULL); + for(unsigned int i = 0; i < number_entries; ++i) + { + nand2cg1s[i] = (ElectricalModel*)getSubInstance("NAND2_CKGate1_" + (String)i); + propagatePortTransitionInfo(nand2cg1s[i], "A", invcg0, "Y"); + propagatePortTransitionInfo(nand2cg1s[i], "B", dec, "Out" + (String)i); + nand2cg1s[i]->use(); + + invcg1s[i] = (ElectricalModel*)getSubInstance("INV_CKGate1_" + (String)i); + propagatePortTransitionInfo(invcg1s[i], "A", nand2cg1s[i], "Y"); + invcg1s[i]->use(); + } + + // Update DFF + vector<ElectricalModel*> dffs(number_entries, NULL); + for(unsigned int i = 0; i < number_entries; ++i) + { + dffs[i] = (ElectricalModel*)getSubInstance("DFF_" + (String)i); + propagatePortTransitionInfo(dffs[i], "D", "In"); + propagatePortTransitionInfo(dffs[i], "CK", invcg1s[i], "Y"); + dffs[i]->use(); + } + + // Update Mux + ElectricalModel* mux = (ElectricalModel*)getSubInstance("Mux"); + for(unsigned int i = 0; i < number_entries; ++i) + { + propagatePortTransitionInfo(mux, "In" + (String)i, dffs[i], "Q"); + } + for(unsigned int i = 0; i < number_addr_bits; ++i) + { + propagatePortTransitionInfo(mux, "Sel" + (String)i, "RDAddr" + (String)i); + } + mux->use(); + + // Set output probability + getOutputPort("Out")->setTransitionInfo(mux->getOutputPort("Out")->getTransitionInfo()); + return; + } +} // namespace DSENT + diff --git a/ext/dsent/model/electrical/DFFRAM.h b/ext/dsent/model/electrical/DFFRAM.h new file mode 100644 index 000000000..0e7626ecd --- /dev/null +++ b/ext/dsent/model/electrical/DFFRAM.h @@ -0,0 +1,33 @@ +#ifndef __DSENT_MODEL_ELECTRICAL_DFFRAM_H__ +#define __DSENT_MODEL_ELECTRICAL_DFFRAM_H__ + +#include "util/CommonType.h" +#include "model/ElectricalModel.h" + +namespace DSENT +{ + class DFFRAM : public ElectricalModel + { + public: + DFFRAM(const String& instance_name_, const TechModel* tech_model_); + virtual ~DFFRAM(); + + public: + // Set a list of properties' name needed to construct model + void initParameters(); + // Set a list of properties' name needed to construct model + void initProperties(); + + // Clone and return a new instance + virtual DFFRAM* clone() const; + + protected: + // Build the model + virtual void constructModel(); + virtual void propagateTransitionInfo(); + + }; // class DFFRAM +} // namespace DSENT + +#endif // __DSENT_MODEL_ELECTRICAL_BUFFER_H__ + diff --git a/ext/dsent/model/electrical/Decoder.cc b/ext/dsent/model/electrical/Decoder.cc new file mode 100644 index 000000000..7629bf8b2 --- /dev/null +++ b/ext/dsent/model/electrical/Decoder.cc @@ -0,0 +1,235 @@ +#include "model/electrical/Decoder.h" + +#include <cmath> + +#include "model/PortInfo.h" +#include "model/EventInfo.h" +#include "model/TransitionInfo.h" +#include "model/std_cells/StdCellLib.h" +#include "model/std_cells/StdCell.h" + +namespace DSENT +{ + using std::ceil; + + Decoder::Decoder(const String& instance_name_, const TechModel* tech_model_) + : ElectricalModel(instance_name_, tech_model_) + { + initParameters(); + initProperties(); + } + + Decoder::~Decoder() + {} + + void Decoder::initParameters() + { + addParameterName("NumberOutputs"); + } + + void Decoder::initProperties() + { + return; + } + + Decoder* Decoder::clone() const + { + // TODO + return NULL; + } + + void Decoder::constructModel() + { + // Get parameters + unsigned int number_outputs = getParameter("NumberOutputs").toUInt(); + + ASSERT(number_outputs > 0, "[Error] " + getInstanceName() + " -> Number of outputs must be > 0!"); + + unsigned int number_addr_bits = (unsigned int)ceil(log2(number_outputs)); + + // Create ports + for(unsigned int i = 0; i < number_addr_bits; ++i) + { + createInputPort("Addr" + (String)i); + } + for(unsigned int i = 0; i < number_outputs; ++i) + { + createOutputPort("Out" + (String)i); + } + + // Create energy, power, and area results + createElectricalResults(); + createElectricalEventResult("Decode"); + Result* decode_event = getEventResult("Decode"); + + getEventInfo("Idle")->setStaticTransitionInfos(); + + if(number_addr_bits == 0) + { + // Do not need a decoder + } + else if(number_addr_bits == 1) + { + const String& inv0_name = "Inv0"; + + StdCell* inv0 = getTechModel()->getStdCellLib()->createStdCell("INV", inv0_name); + inv0->construct(); + + // Connect inputs and outputs + portConnect(inv0, "A", "Addr0"); + portConnect(inv0, "Y", "Out0"); + assign("Out1", "Addr0"); + + // Add area, power, and event results + addSubInstances(inv0, 1.0); + addElectricalSubResults(inv0, 1.0); + decode_event->addSubResult(inv0->getEventResult("INV"), inv0_name, 1.0); + } + else + { + unsigned int number_addr_bits_0 = (unsigned int)ceil((double)number_addr_bits / 2.0); + unsigned int number_addr_bits_1 = (unsigned int)floor((double)number_addr_bits / 2.0); + + unsigned int number_outputs_0 = (unsigned int)pow(2.0, number_addr_bits_0); + unsigned int number_outputs_1 = (unsigned int)ceil((double)number_outputs / (double)number_outputs_0); + + const String& dec0_name = "Dec_way0"; + const String& dec1_name = "Dec_way1"; + vector<String> nand2_names(number_outputs, ""); + vector<String> inv_names(number_outputs, ""); + for(unsigned int i = 0; i < number_outputs; ++i) + { + nand2_names[i] = "NAND2_" + (String)i; + inv_names[i] = "INV_" + (String)i; + } + + Decoder* dec0 = new Decoder(dec0_name, getTechModel()); + dec0->setParameter("NumberOutputs", number_outputs_0); + dec0->construct(); + + Decoder* dec1 = new Decoder(dec1_name, getTechModel()); + dec1->setParameter("NumberOutputs", number_outputs_1); + dec1->construct(); + + vector<StdCell*> nand2s(number_outputs, NULL); + vector<StdCell*> invs(number_outputs, NULL); + for(unsigned int i = 0; i < number_outputs; ++i) + { + nand2s[i] = getTechModel()->getStdCellLib()->createStdCell("NAND2", nand2_names[i]); + nand2s[i]->construct(); + invs[i] = getTechModel()->getStdCellLib()->createStdCell("INV", inv_names[i]); + invs[i]->construct(); + } + + // Connect inputs and outputs + for(unsigned int i = 0; i < number_addr_bits_0; ++i) + { + portConnect(dec0, "Addr" + (String)i, "Addr" + (String)i); + } + for(unsigned int i = 0; i < number_addr_bits_1; ++i) + { + portConnect(dec1, "Addr" + (String)i, "Addr" + (String)(i + number_addr_bits_0)); + } + for(unsigned int i = 0; i < number_outputs_0; ++i) + { + createNet("way0Out" + (String)i); + portConnect(dec0, "Out" + (String)i, "way0Out" + (String)i); + } + for(unsigned int i = 0; i < number_outputs_1; ++i) + { + createNet("way1Out" + (String)i); + portConnect(dec1, "Out" + (String)i, "way1Out" + (String)i); + } + + for(unsigned int i = 0; i < number_outputs; ++i) + { + createNet("nand" + (String)i + "Out"); + portConnect(nand2s[i], "A", "way0Out" + (String)(i%number_outputs_0)); + portConnect(nand2s[i], "B", "way1Out" + (String)((unsigned int)floor(i/number_outputs_0))); + portConnect(nand2s[i], "Y", "nand" + (String)i + "Out"); + portConnect(invs[i], "A", "nand" + (String)i + "Out"); + portConnect(invs[i], "Y", "Out" + (String)i); + } + + // Add area, power, and event results + addSubInstances(dec0, 1.0); + addElectricalSubResults(dec0, 1.0); + decode_event->addSubResult(dec0->getEventResult("Decode"), dec0_name, 1.0); + addSubInstances(dec1, 1.0); + addElectricalSubResults(dec1, 1.0); + decode_event->addSubResult(dec1->getEventResult("Decode"), dec1_name, 1.0); + for(unsigned int i = 0; i < number_outputs; ++i) + { + addSubInstances(nand2s[i], 1.0); + addElectricalSubResults(nand2s[i], 1.0); + decode_event->addSubResult(nand2s[i]->getEventResult("NAND2"), nand2_names[i], 1.0); + + addSubInstances(invs[i], 1.0); + addElectricalSubResults(invs[i], 1.0); + decode_event->addSubResult(invs[i]->getEventResult("INV"), inv_names[i], 1.0); + } + } + return; + } + + void Decoder::propagateTransitionInfo() + { + // The only thing can be updated are the input probabilities + unsigned int number_outputs = getParameter("NumberOutputs").toUInt(); + + unsigned int number_addr_bits = (unsigned int)ceil(log2(number_outputs)); + + if(number_addr_bits == 0) + { + // Do not need a decoder + } + else if(number_addr_bits == 1) + { + ElectricalModel* inv0 = (ElectricalModel*)getSubInstance("Inv0"); + propagatePortTransitionInfo(inv0, "A", "Addr0"); + inv0->use(); + + // Since # addr bits is 1, the output 0 is directly connected + propagatePortTransitionInfo("Out0", inv0, "Y"); + propagatePortTransitionInfo("Out1", "Addr0"); + } + else + { + unsigned int number_addr_bits_0 = (unsigned int)ceil((double)number_addr_bits / 2.0); + unsigned int number_addr_bits_1 = (unsigned int)floor((double)number_addr_bits / 2.0); + + unsigned int number_outputs_0 = (unsigned int)pow(2.0, number_addr_bits_0); + + // Update decoders with probabilities + ElectricalModel* dec0 = (ElectricalModel*)getSubInstance("Dec_way0"); + for(unsigned int i = 0; i < number_addr_bits_0; ++i) + { + propagatePortTransitionInfo(dec0, "Addr" + (String)i, "Addr" + (String)i); + } + dec0->use(); + ElectricalModel* dec1 = (ElectricalModel*)getSubInstance("Dec_way1"); + for(unsigned int i = 0; i < number_addr_bits_1; ++i) + { + propagatePortTransitionInfo(dec1, "Addr" + (String)i, "Addr" + (String)(i + number_addr_bits_0)); + } + dec1->use(); + + for(unsigned int i = 0; i < number_outputs; ++i) + { + ElectricalModel* nand2 = (ElectricalModel*)getSubInstance("NAND2_" + (String)i); + propagatePortTransitionInfo(nand2, "A", dec0, "Out" + (String)(i%number_outputs_0)); + propagatePortTransitionInfo(nand2, "B", dec1, "Out" + (String)((unsigned int)floor(i/number_outputs_0))); + nand2->use(); + + ElectricalModel* inv = (ElectricalModel*)getSubInstance("INV_" + (String)i); + propagatePortTransitionInfo(inv, "A", nand2, "Y"); + inv->use(); + + propagatePortTransitionInfo("Out" + (String)i, inv, "Y"); + } + } + return; + } + +} // namespace DSENT + diff --git a/ext/dsent/model/electrical/Decoder.h b/ext/dsent/model/electrical/Decoder.h new file mode 100644 index 000000000..3c09fc4ef --- /dev/null +++ b/ext/dsent/model/electrical/Decoder.h @@ -0,0 +1,33 @@ +#ifndef __DSENT_MODEL_ELECTRICAL_DECODER_H__ +#define __DSENT_MODEL_ELECTRICAL_DECODER_H__ + +#include "util/CommonType.h" +#include "model/ElectricalModel.h" + +namespace DSENT +{ + class Decoder : public ElectricalModel + { + public: + Decoder(const String& instance_name_, const TechModel* tech_model_); + virtual ~Decoder(); + + public: + // Set a list of properties' name needed to construct model + void initParameters(); + // Set a list of properties' name needed to construct model + void initProperties(); + + // Clone and return a new instance + virtual Decoder* clone() const; + + protected: + // Build the model + virtual void constructModel(); + virtual void propagateTransitionInfo(); + + }; // class Decoder +} // namespace DSENT + +#endif // __DSENT_MODEL_ELECTRICAL_DECODER_H__ + diff --git a/ext/dsent/model/electrical/DemuxTreeDeserializer.cc b/ext/dsent/model/electrical/DemuxTreeDeserializer.cc new file mode 100644 index 000000000..4d74e8db2 --- /dev/null +++ b/ext/dsent/model/electrical/DemuxTreeDeserializer.cc @@ -0,0 +1,378 @@ +#include "model/electrical/DemuxTreeDeserializer.h" + +#include <cmath> + +#include "model/PortInfo.h" +#include "model/TransitionInfo.h" +#include "model/EventInfo.h" +#include "model/std_cells/StdCellLib.h" +#include "model/std_cells/StdCell.h" +#include "model/electrical/Multiplexer.h" +#include "model/timing_graph/ElectricalNet.h" + +namespace DSENT +{ + using std::ceil; + + DemuxTreeDeserializer::DemuxTreeDeserializer(const String& instance_name_, const TechModel* tech_model_) + : ElectricalModel(instance_name_, tech_model_) + { + initParameters(); + initProperties(); + } + + DemuxTreeDeserializer::~DemuxTreeDeserializer() + {} + + void DemuxTreeDeserializer::initParameters() + { + addParameterName("InDataRate"); + addParameterName("OutDataRate"); + addParameterName("OutBits"); //Output width will just be output width / serialization ratio + addParameterName("BitDuplicate", "TRUE"); + return; + } + + void DemuxTreeDeserializer::initProperties() + { + return; + } + + DemuxTreeDeserializer* DemuxTreeDeserializer::clone() const + { + // TODO + return NULL; + } + + void DemuxTreeDeserializer::constructModel() + { + + // Get parameters + double in_data_rate = getParameter("InDataRate"); + double out_data_rate = getParameter("OutDataRate"); + unsigned int out_bits = getParameter("OutBits"); + bool bit_duplicate = getParameter("BitDuplicate"); + + // Calculate deserialization ratio + unsigned int deserialization_ratio = (unsigned int) floor(in_data_rate / out_data_rate); + ASSERT(deserialization_ratio == in_data_rate / out_data_rate, + "[Error] " + getInstanceName() + " -> Cannot have non-integer deserialization ratios!"); + ASSERT((deserialization_ratio & (deserialization_ratio - 1)) == 0, + "[Error] " + getInstanceName() + " -> Deserialization ratio must be a power of 2"); + + // Calculate output width + unsigned int input_bits = out_bits / deserialization_ratio; + ASSERT(out_bits >= deserialization_ratio, "[Error] " + getInstanceName() + + " -> Output width must be >= deserialization ratio!"); + ASSERT(floor((double) out_bits / deserialization_ratio) == input_bits, + "[Error] " + getInstanceName() + " -> Output width must be a multiple of the serialization ratio!"); + + // Store calculated numbers + getGenProperties()->set("DeserializationRatio", deserialization_ratio); + getGenProperties()->set("InputBits", input_bits); + + // Create ports + createInputPort("In", makeNetIndex(0, input_bits-1)); + createInputPort("InCK"); + createOutputPort("Out", makeNetIndex(0, out_bits-1)); + + //Create energy, power, and area results + createElectricalResults(); + createElectricalEventResult("Deserialize"); + getEventInfo("Deserialize")->setTransitionInfo("InCK", TransitionInfo(0.0, (double) deserialization_ratio / 2.0, 0.0)); + // Set conditions during idle state + getEventInfo("Idle")->setStaticTransitionInfos(); + getEventInfo("Idle")->setTransitionInfo("InCK", TransitionInfo(0.0, (double) deserialization_ratio / 2.0, 0.0)); + + // Mark InCK as a false path (since timing tool will do strange stuff due to all the clock divides and stuff) + getNet("InCK")->setFalsePath(true); + + // Create deserializer + if (deserialization_ratio == 1) + { + // No need to do anything, hohoho + assign("Out", "In"); + } + else if (input_bits == 1) + { + //----------------------------------------------------------------- + // Create 2:1 demux deserializer + //----------------------------------------------------------------- + const String& des_dff_way0_name = "DesDFFWay0"; + const String& des_dff_way1_name = "DesDFFWay1"; + const String& des_latch_name = "DesLatch"; + const String& ck_dff_name = "CKDFF"; + const String& ck_inv_name = "CKINV"; + const String& out_way0_name = "OutWay0"; + const String& out_way1_name = "OutWay1"; + const String& mid_way0_name = "MidWay0"; + const String& ck_div2_name = "CK_div2"; + const String& ck_div2_b_name = "CK_div2_b"; + + // Create nets + createNet(out_way0_name); + createNet(out_way1_name); + createNet(mid_way0_name); + createNet(ck_div2_name); + createNet(ck_div2_b_name); + + // Create the dffs and latch needed on both ways + StdCell* des_dff_way0 = getTechModel()->getStdCellLib()->createStdCell("DFFQ", des_dff_way0_name); + des_dff_way0->construct(); + StdCell* des_dff_way1 = getTechModel()->getStdCellLib()->createStdCell("DFFQ", des_dff_way1_name); + des_dff_way1->construct(); + StdCell* des_latch = getTechModel()->getStdCellLib()->createStdCell("LATQ", des_latch_name); + des_latch->construct(); + + // Create clk divide circuit + StdCell* ck_dff = getTechModel()->getStdCellLib()->createStdCell("DFFQ", ck_dff_name); + ck_dff->construct(); + StdCell* ck_inv = getTechModel()->getStdCellLib()->createStdCell("INV", ck_inv_name); + ck_inv->construct(); + + // Connect ports + portConnect(des_dff_way0, "CK", "InCK"); + portConnect(des_dff_way0, "D", mid_way0_name); + portConnect(des_dff_way0, "Q", out_way0_name); + portConnect(des_latch, "G", "InCK"); + portConnect(des_latch, "D", "In"); + portConnect(des_latch, "Q", mid_way0_name); + portConnect(des_dff_way1, "CK", "InCK"); + portConnect(des_dff_way1, "D", "In"); + portConnect(des_dff_way1, "Q", out_way1_name); + portConnect(ck_dff, "CK", "InCK"); + portConnect(ck_dff, "D", ck_div2_b_name); + portConnect(ck_dff, "Q", ck_div2_name); + portConnect(ck_inv, "A", ck_div2_name); + portConnect(ck_inv, "Y", ck_div2_b_name); + + // Add sub instances + addSubInstances(des_dff_way0, 1.0); + addElectricalSubResults(des_dff_way0, 1.0); + addSubInstances(des_dff_way1, 1.0); + addElectricalSubResults(des_dff_way1, 1.0); + addSubInstances(des_latch, 1.0); + addElectricalSubResults(des_latch, 1.0); + addSubInstances(ck_dff, 1.0); + addElectricalSubResults(ck_dff, 1.0); + addSubInstances(ck_inv, 1.0); + addElectricalSubResults(ck_inv, 1.0); + + Result* deserialize = getEventResult("Deserialize"); + deserialize->addSubResult(des_dff_way0->getEventResult("CK"), des_dff_way0_name, 1.0); + deserialize->addSubResult(des_dff_way0->getEventResult("DFFD"), des_dff_way0_name, 1.0); + deserialize->addSubResult(des_dff_way0->getEventResult("DFFQ"), des_dff_way0_name, 1.0); + deserialize->addSubResult(des_dff_way1->getEventResult("CK"), des_dff_way1_name, 1.0); + deserialize->addSubResult(des_dff_way1->getEventResult("DFFD"), des_dff_way1_name, 1.0); + deserialize->addSubResult(des_dff_way1->getEventResult("DFFQ"), des_dff_way1_name, 1.0); + deserialize->addSubResult(des_latch->getEventResult("G"), des_latch_name, 1.0); + deserialize->addSubResult(des_latch->getEventResult("LATD"), des_latch_name, 1.0); + deserialize->addSubResult(des_latch->getEventResult("LATQ"), des_latch_name, 1.0); + deserialize->addSubResult(ck_dff->getEventResult("CK"), ck_dff_name, 1.0); + deserialize->addSubResult(ck_dff->getEventResult("DFFD"), ck_dff_name, 1.0); + deserialize->addSubResult(ck_dff->getEventResult("DFFQ"), ck_dff_name, 1.0); + deserialize->addSubResult(ck_inv->getEventResult("INV"), ck_inv_name, 1.0); + //----------------------------------------------------------------- + + //----------------------------------------------------------------- + // Create Sub-deserializers + //----------------------------------------------------------------- + // Create sub-deserializers + const String& demux_way0_name = "DemuxTree_way0_" + (String) deserialization_ratio + "_to_1"; + const String& demux_way1_name = "DemuxTree_way1_" + (String) deserialization_ratio + "_to_1"; + + DemuxTreeDeserializer* demux_way0 = new DemuxTreeDeserializer(demux_way0_name, getTechModel()); + demux_way0->setParameter("InDataRate", in_data_rate / 2.0); + demux_way0->setParameter("OutDataRate", out_data_rate); + demux_way0->setParameter("OutBits", out_bits / 2); + demux_way0->setParameter("BitDuplicate", "TRUE"); + demux_way0->construct(); + + DemuxTreeDeserializer* demux_way1 = new DemuxTreeDeserializer(demux_way1_name, getTechModel()); + demux_way1->setParameter("InDataRate", in_data_rate / 2.0); + demux_way1->setParameter("OutDataRate", out_data_rate); + demux_way1->setParameter("OutBits", out_bits / 2); + demux_way1->setParameter("BitDuplicate", "TRUE"); + demux_way1->construct(); + + // Connect ports + portConnect(demux_way0, "In", out_way0_name); + portConnect(demux_way0, "InCK", ck_div2_name); + portConnect(demux_way0, "Out", "Out", makeNetIndex(0, out_bits/2-1)); + + portConnect(demux_way1, "In", out_way1_name); + portConnect(demux_way1, "InCK", ck_div2_name); + portConnect(demux_way1, "Out", "Out", makeNetIndex(out_bits/2, out_bits-1)); + + // Add subinstances and area results + addSubInstances(demux_way0, 1.0); + addElectricalSubResults(demux_way0, 1.0); + addSubInstances(demux_way1, 1.0); + addElectricalSubResults(demux_way1, 1.0); + + deserialize->addSubResult(demux_way0->getEventResult("Deserialize"), demux_way0_name, 1.0); + deserialize->addSubResult(demux_way1->getEventResult("Deserialize"), demux_way1_name, 1.0); + //----------------------------------------------------------------- + + } + else if (bit_duplicate) + { + const String& demux_name = "DemuxTree_" + (String) deserialization_ratio + "_to_1"; + + DemuxTreeDeserializer* des_bit = new DemuxTreeDeserializer(demux_name, getTechModel()); + des_bit->setParameter("InDataRate", in_data_rate); + des_bit->setParameter("OutDataRate", out_data_rate); + des_bit->setParameter("OutBits", deserialization_ratio); + des_bit->setParameter("BitDuplicate", "TRUE"); + des_bit->construct(); + + // Create VFI and VFO nets + createNet("InVFI"); + createNet("OutVFO", makeNetIndex(0, deserialization_ratio-1)); + + // Connect ports + portConnect(des_bit, "In", "InVFI"); + portConnect(des_bit, "Out", "OutVFO"); + + // Do VFI and VFO + assignVirtualFanin("InVFI", "In"); + for (unsigned int i = 0; i < input_bits; ++i) + { + portConnect(des_bit, "InCK", "InCK"); + for (unsigned int j = 0; j < deserialization_ratio; ++j) + assignVirtualFanout("Out", makeNetIndex(i*deserialization_ratio + j), "OutVFO", makeNetIndex(j)); + } + // Add subinstances and area results + addSubInstances(des_bit, input_bits); + addElectricalSubResults(des_bit, input_bits); + getEventResult("Deserialize")->addSubResult(des_bit->getEventResult("Deserialize"), demux_name, input_bits); + } + else + { + //Instantiate a bunch of 1 input bit deserializers + for (unsigned int i = 0; i < input_bits; ++i) + { + const String& demux_name = "DemuxTree_" + (String) deserialization_ratio + "_to_1_bit" + (String) i; + + DemuxTreeDeserializer* des_bit = new DemuxTreeDeserializer(demux_name, getTechModel()); + des_bit->setParameter("InDataRate", in_data_rate); + des_bit->setParameter("OutDataRate", out_data_rate); + des_bit->setParameter("OutBits", deserialization_ratio); + des_bit->setParameter("BitDuplicate", "TRUE"); + des_bit->construct(); + + portConnect(des_bit, "In", "In", makeNetIndex(i)); + portConnect(des_bit, "InCK", "InCK"); + portConnect(des_bit, "Out", "Out", makeNetIndex(i*deserialization_ratio, (i+1)*deserialization_ratio-1)); + + addSubInstances(des_bit, 1.0); + addElectricalSubResults(des_bit, 1.0); + getEventResult("Deserialize")->addSubResult(des_bit->getEventResult("Deserialize"), demux_name, 1.0); + } + } + + return; + } + + void DemuxTreeDeserializer::propagateTransitionInfo() + { + // Get parameters + bool bit_duplicate = getParameter("BitDuplicate"); + // Get generated properties + unsigned int deserialization_ratio = getGenProperties()->get("DeserializationRatio"); + unsigned int input_bits = getGenProperties()->get("InputBits"); + + // Calculate output transitions and activities + if (deserialization_ratio == 1) + { + // If no deserialization, then just propagate input transition info to output port + propagatePortTransitionInfo("Out", "In"); + } + else if (input_bits == 1) + { + const String& des_dff_way0_name = "DesDFFWay0"; + const String& des_dff_way1_name = "DesDFFWay1"; + const String& des_latch_name = "DesLatch"; + const String& ck_dff_name = "CKDFF"; + const String& ck_inv_name = "CKINV"; + + // Sub-deserializer names + const String& demux_way0_name = "DemuxTree_way0_" + (String) deserialization_ratio + "_to_1"; + const String& demux_way1_name = "DemuxTree_way1_" + (String) deserialization_ratio + "_to_1"; + + // Update transition info for deserialization registers/latches + ElectricalModel* des_latch = (ElectricalModel*) getSubInstance(des_latch_name); + propagatePortTransitionInfo(des_latch, "G", "InCK"); + propagatePortTransitionInfo(des_latch, "D", "In"); + des_latch->use(); + + ElectricalModel* des_dff_way0 = (ElectricalModel*) getSubInstance(des_dff_way0_name); + propagatePortTransitionInfo(des_dff_way0, "CK", "InCK"); + propagatePortTransitionInfo(des_dff_way0, "D", des_latch, "Q"); + des_dff_way0->use(); + + ElectricalModel* des_dff_way1 = (ElectricalModel*) getSubInstance(des_dff_way1_name); + propagatePortTransitionInfo(des_dff_way1, "CK", "InCK"); + propagatePortTransitionInfo(des_dff_way1, "D", "In"); + des_dff_way1->use(); + + // Get input transitions of input clock + double P01_CK = getInputPort("InCK")->getTransitionInfo().getNumberTransitions01(); + // Update transition info for clk division DFF + ElectricalModel* ck_dff = (ElectricalModel*) getSubInstance(ck_dff_name); + propagatePortTransitionInfo(ck_dff, "CK", "InCK"); + // Since it is a clock divider, P01 is D and Q are simply half the P01 of D and Q of + // the input clock + if (P01_CK != 0) ck_dff->getInputPort("D")->setTransitionInfo(TransitionInfo(0.0, P01_CK * 0.5, 0.0)); + else ck_dff->getInputPort("D")->setTransitionInfo(TransitionInfo(0.5, 0.0, 0.5)); + + ck_dff->use(); + // Update transition info of clk divided inverter + ElectricalModel* ck_inv = (ElectricalModel*) getSubInstance(ck_inv_name); + propagatePortTransitionInfo(ck_inv, "A", ck_dff, "Q"); + ck_inv->use(); + + // Update transition info for next demux stages + ElectricalModel* demux_way0 = (ElectricalModel*) getSubInstance(demux_way0_name); + propagatePortTransitionInfo(demux_way0, "In", des_dff_way0, "Q"); + propagatePortTransitionInfo(demux_way0, "InCK", ck_dff, "Q"); + demux_way0->use(); + ElectricalModel* demux_way1 = (ElectricalModel*) getSubInstance(demux_way1_name); + propagatePortTransitionInfo(demux_way1, "In", des_dff_way1, "Q"); + propagatePortTransitionInfo(demux_way1, "InCK", ck_dff, "Q"); + demux_way1->use(); + + propagatePortTransitionInfo("Out", demux_way0, "Out"); + } + else if (bit_duplicate) + { + // Propagate transition info + const String& demux_name = "DemuxTree_" + (String) deserialization_ratio + "_to_1"; + ElectricalModel* demux = (ElectricalModel*) getSubInstance(demux_name); + propagatePortTransitionInfo(demux, "In", "In"); + propagatePortTransitionInfo(demux, "InCK", "InCK"); + demux->use(); + + propagatePortTransitionInfo("Out", demux, "Out"); + } + else + { + // Set output probability to be average that of probabilties of each output bit + // Update all 1 bit deserializers + for (unsigned int i = 0; i < input_bits; ++i) + { + const String& demux_name = "DemuxTree_" + (String) deserialization_ratio + "_to_1_bit" + (String) i; + ElectricalModel* demux_bit = (ElectricalModel*) getSubInstance(demux_name); + propagatePortTransitionInfo(demux_bit, "In", "In"); + propagatePortTransitionInfo(demux_bit, "InCK", "InCK"); + demux_bit->use(); + + propagatePortTransitionInfo("Out", demux_bit, "Out"); + } + } + + return; + } + +} // namespace DSENT + diff --git a/ext/dsent/model/electrical/DemuxTreeDeserializer.h b/ext/dsent/model/electrical/DemuxTreeDeserializer.h new file mode 100644 index 000000000..216614193 --- /dev/null +++ b/ext/dsent/model/electrical/DemuxTreeDeserializer.h @@ -0,0 +1,33 @@ +#ifndef __DSENT_MODEL_ELECTRICAL_MULTIPHASEDESERIALIZER_H__ +#define __DSENT_MODEL_ELECTRICAL_MULTIPHASEDESERIALIZER_H__ + +#include "util/CommonType.h" +#include "model/ElectricalModel.h" + +namespace DSENT +{ + class DemuxTreeDeserializer : public ElectricalModel + { + public: + DemuxTreeDeserializer(const String& instance_name_, const TechModel* tech_model_); + virtual ~DemuxTreeDeserializer(); + + public: + // Set a list of properties' name needed to construct model + void initParameters(); + // Set a list of properties' name needed to construct model + void initProperties(); + + // Clone and return a new instance + virtual DemuxTreeDeserializer* clone() const; + + protected: + // Build the model + virtual void constructModel(); + virtual void propagateTransitionInfo(); + + }; // class DemuxTreeDeserializer +} // namespace DSENT + +#endif // __DSENT_MODEL_ELECTRICAL_MULTIPHASEDESERIALIZER_H__ + diff --git a/ext/dsent/model/electrical/MatrixArbiter.cc b/ext/dsent/model/electrical/MatrixArbiter.cc new file mode 100644 index 000000000..7f72abd63 --- /dev/null +++ b/ext/dsent/model/electrical/MatrixArbiter.cc @@ -0,0 +1,434 @@ +#include "model/electrical/MatrixArbiter.h" + +#include <cmath> +#include <vector> + +#include "model/PortInfo.h" +#include "model/EventInfo.h" +#include "model/TransitionInfo.h" +#include "model/ModelGen.h" +#include "model/std_cells/StdCell.h" +#include "model/std_cells/StdCellLib.h" + +namespace DSENT +{ + using std::abs; + using std::vector; + + MatrixArbiter::MatrixArbiter(const String& instance_name_, const TechModel* tech_model_) + : ElectricalModel(instance_name_, tech_model_) + { + initParameters(); + initProperties(); + } + + MatrixArbiter::~MatrixArbiter() + {} + + void MatrixArbiter::initParameters() + { + addParameterName("NumberRequests"); + return; + } + + void MatrixArbiter::initProperties() + { + return; + } + + MatrixArbiter* MatrixArbiter::clone() const + { + // TODO + return NULL; + } + + void MatrixArbiter::constructModel() + { + // Get parameters + unsigned int number_requests = getParameter("NumberRequests").toUInt(); + + ASSERT(number_requests > 0, "[Error] " + getInstanceName() + + " -> Number of requests must be > 0!"); + + // Connect ports + createInputPort("CK"); + for(unsigned int i = 0; i < number_requests; ++i) + { + createInputPort("Request" + (String)i); + createOutputPort("Grant" + (String)i); + } + + // Create area, power, event results + createElectricalResults(); + getEventInfo("Idle")->setStaticTransitionInfos(); + getEventInfo("Idle")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0)); +// for(unsigned int i = 0; i <= number_requests; ++i) +// { +// // Create arbitrate event with i requests +// createElectricalEventResult("Arbitrate" + (String)i); +// EventInfo* event_info = getEventInfo("Arbitrate" + (String)i); +// event_info->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0)); +// +// for(unsigned int j = 0; j < i; ++j) +// { +// event_info->setTransitionInfo("Request" + (String)j, TransitionInfo(0.0, 0.0, 1.0)); +// } +// for(unsigned int j = i; j < number_requests; ++j) +// { +// event_info->setTransitionInfo("Request" + (String)j, TransitionInfo(1.0, 0.0, 0.0)); +// +// } +// //double P_0 = (double)(number_requests - i) / (double)(number_requests); +// //double P_1 = (double)(i) / (double)(number_requests); +// //TransitionInfo trans(P_0 * P_0, P_0 * P_1, P_1 * P_1); +// +// //for(unsigned int j = 0; j < number_requests; ++j) +// //{ +// // event_info->setTransitionInfo("Request" + (String)j, trans); +// //} +// } + createElectricalEventResult("Arbitrate"); + getEventInfo("Arbitrate")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0)); + for(unsigned int i = 0; i < number_requests; ++i) + { + getEventInfo("Arbitrate")->setTransitionInfo("Request" + (String)i, TransitionInfo(0.25, 0.25, 0.25)); + } + + if(number_requests == 1) + { + assign("Grant0", "Request0"); + } + else + { + // Init components + vector<String> g_inv_names(number_requests, ""); + vector<StdCell*> g_invs(number_requests, NULL); + vector<String> g_and2_names(number_requests, ""); + vector<StdCell*> g_and2s(number_requests, NULL); + for(unsigned int i = 0; i < number_requests; ++i) + { + g_inv_names[i] = "G_INV" + (String)i; + g_and2_names[i] = "G_AND2" + (String)i; + g_invs[i] = getTechModel()->getStdCellLib()->createStdCell("INV", g_inv_names[i]); + g_invs[i]->construct(); + g_and2s[i] = getTechModel()->getStdCellLib()->createStdCell("AND2", g_and2_names[i]); + g_and2s[i]->construct(); + } + + unsigned int number_states = (number_requests - 1) * number_requests / 2; + + vector<String> w_or2_names(number_states, ""); + vector<StdCell*> w_or2s(number_states, NULL); + vector<String> w_and2_names(number_states, ""); + vector<StdCell*> w_and2s(number_states, NULL); + vector<String> w_inv_names(number_states, ""); + vector<StdCell*> w_invs(number_states, NULL); + vector<String> w_dff_names(number_states, ""); + vector<StdCell*> w_dffs(number_states, NULL); + vector<String> dis_and2_names(number_states * 2, ""); + vector<StdCell*> dis_and2s(number_states * 2, NULL); + vector<String> dis_inv_names(number_states, ""); + vector<StdCell*> dis_invs(number_states, NULL); + unsigned int state_count = 0; + for(unsigned int i = 0; i < number_requests; ++i) + { + for(unsigned int j = i + 1; j < number_requests; ++j) + { + w_or2_names[state_count] = String::format("W_OR2_%d_%d", i, j); + w_and2_names[state_count] = String::format("W_AND2_%d_%d", i, j); + w_inv_names[state_count] = String::format("W_INV_%d_%d", i, j); + w_dff_names[state_count] = String::format("W_DFF_%d_%d", i, j); + w_or2s[state_count] = getTechModel()->getStdCellLib()->createStdCell("OR2", w_or2_names[state_count]); + w_or2s[state_count]->construct(); + w_and2s[state_count] = getTechModel()->getStdCellLib()->createStdCell("AND2", w_and2_names[state_count]); + w_and2s[state_count]->construct(); + w_invs[state_count] = getTechModel()->getStdCellLib()->createStdCell("INV", w_inv_names[state_count]); + w_invs[state_count]->construct(); + w_dffs[state_count] = getTechModel()->getStdCellLib()->createStdCell("DFFQ", w_dff_names[state_count]); + w_dffs[state_count]->construct(); + + dis_inv_names[state_count] = String::format("Dis_INV_%d_%d", i, j); + dis_and2_names[state_count] = String::format("Dis_AND2_%d_%d", i, j); + dis_and2_names[state_count + number_states] = String::format("Dis_AND2_%d_%d", j, i); + dis_invs[state_count] = getTechModel()->getStdCellLib()->createStdCell("INV", dis_inv_names[state_count]); + dis_invs[state_count]->construct(); + dis_and2s[state_count] = getTechModel()->getStdCellLib()->createStdCell("AND2", dis_and2_names[state_count]); + dis_and2s[state_count]->construct(); + dis_and2s[state_count + number_states] = getTechModel()->getStdCellLib()->createStdCell("AND2", dis_and2_names[state_count + number_states]); + dis_and2s[state_count + number_states]->construct(); + state_count++; + } + } + + vector<String> dis_or_names(number_requests, ""); + vector<ElectricalModel*> dis_ors(number_requests, NULL); + for(unsigned int i = 0; i < number_requests; ++i) + { + dis_or_names[i] = "Dis_OR" + (String)i; + dis_ors[i] = (ElectricalModel*)ModelGen::createModel("OR", dis_or_names[i], getTechModel()); + dis_ors[i]->setParameter("NumberInputs", number_requests-1); + dis_ors[i]->setParameter("NumberBits", 1); + dis_ors[i]->construct(); + } + + state_count = 0; + for(unsigned int i = 0; i < number_requests; ++i) + { + createNet("Dis_OR_Out" + (String)i); + createNet("G_INV_Out" + (String)i); + portConnect(g_invs[i], "A", "Dis_OR_Out" + (String)i); + portConnect(g_invs[i], "Y", "G_INV_Out" + (String)i); + portConnect(g_and2s[i], "A", "Request" + (String)i); + portConnect(g_and2s[i], "B", "G_INV_Out" + (String)i); + portConnect(g_and2s[i], "Y", "Grant" + (String)i); + + for(unsigned int j = i + 1; j < number_requests; ++j) + { + createNet(String::format("W_INV_Out_%d_%d", i, j)); + createNet(String::format("W_OR2_Out_%d_%d", i, j)); + createNet(String::format("W_AND2_Out_%d_%d", i, j)); + createNet(String::format("W_DFF_Out_%d_%d", i, j)); + portConnect(w_invs[state_count], "A", "Grant" + (String)i); + portConnect(w_invs[state_count], "Y", String::format("W_INV_Out_%d_%d", i, j)); + portConnect(w_or2s[state_count], "A", String::format("W_DFF_Out_%d_%d", i, j)); + portConnect(w_or2s[state_count], "B", "Grant" + (String)j); + portConnect(w_or2s[state_count], "Y", String::format("W_OR2_Out_%d_%d", i, j)); + portConnect(w_and2s[state_count], "A", String::format("W_OR2_Out_%d_%d", i, j)); + portConnect(w_and2s[state_count], "B", String::format("W_INV_Out_%d_%d", i, j)); + portConnect(w_and2s[state_count], "Y", String::format("W_AND2_Out_%d_%d", i, j)); + portConnect(w_dffs[state_count], "D", String::format("W_AND2_Out_%d_%d", i, j)); + portConnect(w_dffs[state_count], "CK", "CK"); + portConnect(w_dffs[state_count], "Q", String::format("W_DFF_Out_%d_%d", i, j)); + + createNet(String::format("Dis_AND2_Out_%d_%d", i, j)); + createNet(String::format("Dis_AND2_Out_%d_%d", j, i)); + createNet(String::format("Dis_INV_Out_%d_%d", j, i)); + portConnect(dis_and2s[state_count], "A", "Request" + (String)i); + portConnect(dis_and2s[state_count], "B", String::format("W_DFF_Out_%d_%d", i, j)); + portConnect(dis_and2s[state_count], "Y", String::format("Dis_AND2_Out_%d_%d", i, j)); + + portConnect(dis_invs[state_count], "A", String::format("W_DFF_Out_%d_%d", i, j)); + portConnect(dis_invs[state_count], "Y", String::format("Dis_INV_Out_%d_%d", j, i)); + portConnect(dis_and2s[state_count + number_states], "A", "Request" + (String)j); + portConnect(dis_and2s[state_count + number_states], "B", String::format("Dis_INV_Out_%d_%d", j, i)); + portConnect(dis_and2s[state_count + number_states], "Y", String::format("Dis_AND2_Out_%d_%d", j, i)); + + state_count++; + } + } + for(unsigned int i = 0; i < number_requests; ++i) + { + unsigned int k = 0; + for(unsigned int j = 0; j < number_requests; ++j) + { + if(i != j) + { + portConnect(dis_ors[i], "In" + (String)k, String::format("Dis_AND2_Out_%d_%d", j, i)); + k++; + } + } + portConnect(dis_ors[i], "Out", "Dis_OR_Out" + (String)i); + } + + // Add instances + for(unsigned int i = 0; i < number_requests; ++i) + { + addSubInstances(g_invs[i], 1.0); + addElectricalSubResults(g_invs[i], 1.0); + addSubInstances(g_and2s[i], 1.0); + addElectricalSubResults(g_and2s[i], 1.0); + addSubInstances(dis_ors[i], 1.0); + addElectricalSubResults(dis_ors[i], 1.0); + } + for(unsigned int i = 0; i < number_states; ++i) + { + addSubInstances(w_or2s[i], 1.0); + addElectricalSubResults(w_or2s[i], 1.0); + addSubInstances(w_and2s[i], 1.0); + addElectricalSubResults(w_and2s[i], 1.0); + addSubInstances(w_invs[i], 1.0); + addElectricalSubResults(w_invs[i], 1.0); + addSubInstances(w_dffs[i], 1.0); + addElectricalSubResults(w_dffs[i], 1.0); + addSubInstances(dis_and2s[i], 1.0); + addElectricalSubResults(dis_and2s[i], 1.0); + addSubInstances(dis_and2s[i + number_states], 1.0); + addElectricalSubResults(dis_and2s[i + number_states], 1.0); + addSubInstances(dis_invs[i], 1.0); + addElectricalSubResults(dis_invs[i], 1.0); + } + + // Update event + //for(unsigned int i = 0; i <= number_requests; ++i) + //{ + //Result* arb_event = getEventResult("Arbitrate" + (String)i); + Result* arb_event = getEventResult("Arbitrate"); + for(unsigned int j = 0; j < number_requests; ++j) + { + arb_event->addSubResult(g_invs[j]->getEventResult("INV"), g_inv_names[j], 1.0); + arb_event->addSubResult(g_and2s[j]->getEventResult("AND2"), g_and2_names[j], 1.0); + arb_event->addSubResult(dis_ors[j]->getEventResult("OR"), dis_or_names[j], 1.0); + } + for(unsigned int j = 0; j < number_states; ++j) + { + arb_event->addSubResult(w_or2s[j]->getEventResult("OR2"), w_or2_names[j], 1.0); + arb_event->addSubResult(w_and2s[j]->getEventResult("AND2"), w_and2_names[j], 1.0); + arb_event->addSubResult(w_invs[j]->getEventResult("INV"), w_inv_names[j], 1.0); + arb_event->addSubResult(w_dffs[j]->getEventResult("DFFD"), w_dff_names[j], 1.0); + arb_event->addSubResult(w_dffs[j]->getEventResult("DFFQ"), w_dff_names[j], 1.0); + arb_event->addSubResult(w_dffs[j]->getEventResult("CK"), w_dff_names[j], 1.0); + arb_event->addSubResult(dis_and2s[j]->getEventResult("AND2"), dis_and2_names[j], 1.0); + arb_event->addSubResult(dis_and2s[j + number_states]->getEventResult("AND2"), dis_and2_names[j + number_states], 1.0); + arb_event->addSubResult(dis_invs[j]->getEventResult("INV"), dis_inv_names[j], 1.0); + } + //} + } + return; + } + + void MatrixArbiter::propagateTransitionInfo() + { + // Get parameters + unsigned int number_requests = getParameter("NumberRequests").toUInt(); + + if(number_requests == 1) + { + propagatePortTransitionInfo("Grant0", "Request0"); + } + else + { + unsigned int number_states = (number_requests - 1) * number_requests / 2; + + vector<ElectricalModel*> g_and2s(number_requests, NULL); + vector<ElectricalModel*> g_invs(number_requests, NULL); + vector<ElectricalModel*> w_invs(number_states, NULL); + vector<ElectricalModel*> w_or2s(number_states, NULL); + vector<ElectricalModel*> w_and2s(number_states, NULL); + vector<ElectricalModel*> w_dffs(number_states, NULL); + vector<ElectricalModel*> dis_invs(number_states, NULL); + vector<ElectricalModel*> dis_and2s(number_requests * number_requests, NULL); + vector<ElectricalModel*> dis_ors(number_requests, NULL); + for(unsigned int i = 0; i < number_requests; ++i) + { + g_and2s[i] = (ElectricalModel*)getSubInstance("G_AND2" + (String)i); + g_invs[i] = (ElectricalModel*)getSubInstance("G_INV" + (String)i); + dis_ors[i] = (ElectricalModel*)getSubInstance("Dis_OR" + (String)i); + } + unsigned int state_count = 0; + for(unsigned int i = 0; i < number_requests; ++i) + { + for(unsigned int j = i + 1; j < number_requests; ++j) + { + w_invs[state_count] = (ElectricalModel*)getSubInstance(String::format("W_INV_%d_%d", i, j)); + w_or2s[state_count] = (ElectricalModel*)getSubInstance(String::format("W_OR2_%d_%d", i, j)); + w_and2s[state_count] = (ElectricalModel*)getSubInstance(String::format("W_AND2_%d_%d", i, j)); + w_dffs[state_count] = (ElectricalModel*)getSubInstance(String::format("W_DFF_%d_%d", i, j)); + dis_invs[state_count] = (ElectricalModel*)getSubInstance(String::format("Dis_INV_%d_%d", i, j)); + dis_and2s[i * number_requests + j] = (ElectricalModel*)getSubInstance(String::format("Dis_AND2_%d_%d", i, j)); + dis_and2s[j * number_requests + i] = (ElectricalModel*)getSubInstance(String::format("Dis_AND2_%d_%d", j, i)); + + w_dffs[state_count]->getInputPort("D")->setTransitionInfo(TransitionInfo(0.5, 0.0, 0.5)); + propagatePortTransitionInfo(w_dffs[state_count], "CK", "CK"); + w_dffs[state_count]->use(); + + state_count++; + } + } + + unsigned int iteration = 1; + unsigned int max_number_iterations = 10; + //vector<TransitionInfo> trans_vector(number_states, TransitionInfo(0.0, 0.0, 1.0)); + //vector<double> total_P_vector(number_states, 0.0); + while(iteration < max_number_iterations) + { +// for(unsigned int i = 0; i < number_states; ++i) +// { +// w_dffs[i]->getInputPort("D")->setTransitionInfo(trans_vector[i]); +// propagatePortTransitionInfo(w_dffs[i], "CK", "CK"); +// w_dffs[i]->use(); +// } + state_count = 0; + for(unsigned int i = 0; i < number_requests; ++i) + { + for(unsigned int j = i + 1; j < number_requests; ++j) + { + propagatePortTransitionInfo(dis_and2s[i * number_requests + j], "A", "Request" + (String)i); + propagatePortTransitionInfo(dis_and2s[i * number_requests + j], "B", w_dffs[state_count], "Q"); + dis_and2s[i * number_requests + j]->use(); + propagatePortTransitionInfo(dis_invs[state_count], "A", w_dffs[state_count], "Q"); + dis_invs[state_count]->use(); + propagatePortTransitionInfo(dis_and2s[j * number_requests + i], "A", "Request" + (String)j); + propagatePortTransitionInfo(dis_and2s[j * number_requests + i], "B", dis_invs[state_count], "Y"); + dis_and2s[j * number_requests + i]->use(); + + state_count++; + } + } + for(unsigned int i = 0; i < number_requests; ++i) + { + unsigned int k = 0; + for(unsigned int j = 0; j < number_requests; ++j) + { + if(i != j) + { + propagatePortTransitionInfo(dis_ors[i], "In" + (String)k, dis_and2s[j * number_requests + i], "Y"); + k++; + } + } + dis_ors[i]->use(); + } + for(unsigned int i = 0; i < number_requests; ++i) + { + propagatePortTransitionInfo(g_invs[i], "A", dis_ors[i], "Out"); + g_invs[i]->use(); + propagatePortTransitionInfo(g_and2s[i], "A", "Request" + (String)i); + propagatePortTransitionInfo(g_and2s[i], "B", g_invs[i], "Y"); + g_and2s[i]->use(); + } + state_count = 0; + for(unsigned int i = 0; i < number_requests; ++i) + { + for(unsigned int j = i + 1; j < number_requests; ++j) + { + propagatePortTransitionInfo(w_invs[state_count], "A", g_and2s[i], "Y"); + w_invs[state_count]->use(); + propagatePortTransitionInfo(w_or2s[state_count], "A", w_dffs[state_count], "Q"); + propagatePortTransitionInfo(w_or2s[state_count], "B", g_and2s[j], "Y"); + w_or2s[state_count]->use(); + propagatePortTransitionInfo(w_and2s[state_count], "A", w_or2s[state_count], "Y"); + propagatePortTransitionInfo(w_and2s[state_count], "B", w_invs[state_count], "Y"); + w_and2s[state_count]->use(); + propagatePortTransitionInfo(w_dffs[state_count], "D", w_and2s[state_count], "Y"); + propagatePortTransitionInfo(w_dffs[state_count], "CK", "CK"); + w_dffs[state_count]->use(); + state_count++; + } + } + +// for(unsigned int i = 0; i < number_states; ++i) +// { +// const TransitionInfo& new_trans = w_dffs[i]->getOutputPort("Q")->getTransitionInfo(); +// total_P_vector[i] += new_trans.getProbability1(); +// trans_vector[i] = TransitionInfo((1.0 - total_P_vector[i] / iteration) * (1.0 - total_P_vector[i] / iteration), +// (1.0 - total_P_vector[i] / iteration) * (total_P_vector[i] / iteration), +// (total_P_vector[i] / iteration) * (total_P_vector[i] / iteration)); +// } +// +// for(unsigned int i = 0; i < number_requests; ++i) +// { +// g_and2s[i]->getOutputPort("Y")->getTransitionInfo().print(cout); +// } +// cout << endl; + iteration++; + } + + for(unsigned int i = 0; i < number_requests; ++i) + { + propagatePortTransitionInfo("Grant" + (String)i, g_and2s[i], "Y"); + } + } + + return; + } +} // namespace DSENT + diff --git a/ext/dsent/model/electrical/MatrixArbiter.h b/ext/dsent/model/electrical/MatrixArbiter.h new file mode 100644 index 000000000..59a6786ab --- /dev/null +++ b/ext/dsent/model/electrical/MatrixArbiter.h @@ -0,0 +1,33 @@ +#ifndef __DSENT_MODEL_ELECTRICAL_MATRIX_ARBITER_H__ +#define __DSENT_MODEL_ELECTRICAL_MATRIX_ARBITER_H__ + +#include "util/CommonType.h" +#include "model/ElectricalModel.h" + +namespace DSENT +{ + class MatrixArbiter : public ElectricalModel + { + public: + MatrixArbiter(const String& instance_name_, const TechModel* tech_model_); + virtual ~MatrixArbiter(); + + public: + // Set a list of properties' name needed to construct model + void initParameters(); + // Set a list of properties' name needed to construct model + void initProperties(); + + // Clone and return a new instance + virtual MatrixArbiter* clone() const; + + protected: + // Build the model + virtual void constructModel(); + virtual void propagateTransitionInfo(); + + }; // class MatrixArbiter +} // namespace DSENT + +#endif // __DSENT_MODEL_ELECTRICAL_MATRIX_ARBITER_H__ + diff --git a/ext/dsent/model/electrical/Multiplexer.cc b/ext/dsent/model/electrical/Multiplexer.cc new file mode 100644 index 000000000..f51f43b4c --- /dev/null +++ b/ext/dsent/model/electrical/Multiplexer.cc @@ -0,0 +1,347 @@ +#include "model/electrical/Multiplexer.h" + +#include <cmath> + +#include "model/PortInfo.h" +#include "model/TransitionInfo.h" +#include "model/EventInfo.h" +#include "model/timing_graph/ElectricalDriverMultiplier.h" +#include "model/timing_graph/ElectricalNet.h" +#include "model/std_cells/StdCell.h" +#include "model/std_cells/StdCellLib.h" + +namespace DSENT +{ + Multiplexer::Multiplexer(const String& instance_name_, const TechModel* tech_model_) + : ElectricalModel(instance_name_, tech_model_) + { + initParameters(); + initProperties(); + } + + Multiplexer::~Multiplexer() + {} + + void Multiplexer::initParameters() + { + addParameterName("NumberInputs"); + addParameterName("NumberBits"); + addParameterName("BitDuplicate", "TRUE"); + addParameterName("IsTopLevel", "TRUE"); + return; + } + + void Multiplexer::initProperties() + { + return; + } + + Multiplexer* Multiplexer::clone() const + { + return NULL; + } + + void Multiplexer::constructModel() + { + // Get parameters + unsigned int number_bits = (unsigned int) getParameter("NumberBits"); + unsigned int number_inputs = (unsigned int) getParameter("NumberInputs"); + unsigned int number_selects = (unsigned int) ceil(log2((double) number_inputs)); + bool bit_duplicate = (bool) getParameter("BitDuplicate"); + bool is_top_level = getParameter("IsTopLevel").toBool(); + + ASSERT(number_inputs > 0, "[Error] " + getInstanceName() + " -> Number of inputs must be > 0!"); + ASSERT(number_bits > 0, "[Error] " + getInstanceName() + " -> Number of bits must be > 0!"); + + //Construct electrical ports and nets + //Create each input port + for(unsigned int i = 0; i < number_inputs; ++i) + createInputPort( "In" + (String) i, makeNetIndex(0, number_bits-1)); + //Create select signals + for(unsigned int i = 0; i < number_selects; ++i) + { + createInputPort( "Sel" + (String)i); + } + //Create output + createOutputPort( "Out", makeNetIndex(0, number_bits-1)); + + //Create energy, power, and area results + createElectricalResults(); + getEventInfo("Idle")->setStaticTransitionInfos(); + createElectricalEventResult("Mux"); + + //Number of inputs on the 0 side + unsigned int inputs_0 = (unsigned int) ceil((double) number_inputs / 2.0); + unsigned int selects_0 = (unsigned int) ceil(log2((double) inputs_0)); + //Number of inputs on the 1 side + unsigned int inputs_1 = (unsigned int) floor((double) number_inputs / 2.0); + unsigned int selects_1 = (unsigned int) ceil(log2((double) inputs_1)); + + //Depending on whether we want to create a 1-bit instance and have it multiplied + //up by number of bits or actually instantiate number_bits of 1-bit instances. + //Recursively instantiates smaller multiplexers + if (bit_duplicate || number_bits == 1) + { + //If it is just a 1-input multiplexer, just connect output to input and be done + if (number_inputs == 1) + { + assign("Out", "In0"); + } + else + { + //If it is more than 1 input, instantiate two sub multiplexers (Mux_way0 and Mux_way1) + //and create a final 2:1 mux (muxf) to select between them + String mux0_name = "Mux_way0"; + String mux1_name = "Mux_way1"; + String muxf_name = "Mux2_i" + (String)number_inputs; + + Multiplexer* mux0 = new Multiplexer(mux0_name, getTechModel()); + mux0->setParameter("NumberInputs", inputs_0); + mux0->setParameter("NumberBits", 1); + mux0->setParameter("BitDuplicate", "TRUE"); + mux0->setParameter("IsTopLevel", "FALSE"); + mux0->construct(); + + Multiplexer* mux1 = new Multiplexer(mux1_name, getTechModel()); + mux1->setParameter("NumberInputs", inputs_1); + mux1->setParameter("NumberBits", 1); + mux1->setParameter("BitDuplicate", "TRUE"); + mux1->setParameter("IsTopLevel", "FALSE"); + mux1->construct(); + + StdCell* muxf = getTechModel()->getStdCellLib()->createStdCell("MUX2", muxf_name); + muxf->construct(); + + // TODO hack + // create selector driver at the top level + if(is_top_level) + { + for(unsigned int i = 0; i < number_selects; ++i) + { + StdCell* selinv0 = getTechModel()->getStdCellLib()->createStdCell("INV", String::format("Sel%dInv0", i)); + StdCell* selinv1 = getTechModel()->getStdCellLib()->createStdCell("INV", String::format("Sel%dInv1", i)); + selinv0->construct(); + selinv1->construct(); + + addSubInstances(selinv0, 1.0); + addElectricalSubResults(selinv0, 1.0); + addSubInstances(selinv1, 1.0); + addElectricalSubResults(selinv1, 1.0); + getEventResult("Mux")->addSubResult(selinv0->getEventResult("INV"), String::format("Sel%dInv0", i), 1.0); + getEventResult("Mux")->addSubResult(selinv1->getEventResult("INV"), String::format("Sel%dInv1", i), 1.0); + } + } + + //Create outputs of way0 and way1 multiplexers with final mux + createNet("way0Out"); + createNet("way1Out"); + portConnect(mux0, "Out", "way0Out"); + portConnect(mux1, "Out", "way1Out"); + portConnect(muxf, "A", "way0Out"); + portConnect(muxf, "B", "way1Out"); + + // TODO hack + // Connect selector bits + if(is_top_level) + { + for(unsigned int i = 0; i < number_selects; ++i) + { + ElectricalModel* selinv0 = (ElectricalModel*)getSubInstance(String::format("Sel%dInv0", i)); + ElectricalModel* selinv1 = (ElectricalModel*)getSubInstance(String::format("Sel%dInv1", i)); + createNet("SelInv" + (String)i); + createNet("SelBuf" + (String)i); + portConnect(selinv0, "A", "Sel" + (String)i); + portConnect(selinv0, "Y", "SelInv" + (String)i); + portConnect(selinv1, "A", "SelInv" + (String)i); + portConnect(selinv1, "Y", "SelBuf" + (String)i); + } + } + //Connect inputs to the sub multiplexers. + //Note that multiple inputs are connected to the mux0 and mux1 input and the + //selector signals are connected multiple times. This is just so that everything + //is loaded appropriately since bit duplication is applied + for (unsigned int n = 0; n < number_bits; ++n) + { + //Connect inputs + for (unsigned int i = 0; i < inputs_0; ++i) + portConnect(mux0, "In" + (String) i, "In" + (String) i, makeNetIndex(n)); + for (unsigned int i = 0; i < inputs_1; ++i) + portConnect(mux1, "In" + (String) i, "In" + (String) (i + inputs_0), makeNetIndex(n)); + // TODO hack + if(is_top_level) + { + //Connect selector bits + for (unsigned int i = 0; i < selects_0; ++i) + portConnect(mux0, "Sel" + (String)i, "SelBuf" + (String)i); + for (unsigned int i = 0; i < selects_1; ++i) + portConnect(mux1, "Sel" + (String)i, "SelBuf" + (String)i); + portConnect(muxf, "S0", "SelBuf" + (String)(number_selects - 1)); + } + else + { + //Connect selector bits + for (unsigned int i = 0; i < selects_0; ++i) + portConnect(mux0, "Sel" + (String)i, "Sel" + (String)i); + for (unsigned int i = 0; i < selects_1; ++i) + portConnect(mux1, "Sel" + (String)i, "Sel" + (String)i); + portConnect(muxf, "S0", "Sel" + (String)(number_selects - 1)); + } + } + + //Connect final mux to outputs + //Because we use bit duplication and so there is only only one multiplexer + //instance, we must use driver multiplier to drive each output appropriately + if (number_bits == 1) + portConnect(muxf, "Y", "Out"); + else + { + createNet("OutTemp"); + createDriverMultiplier("OutMult"); + ElectricalDriverMultiplier* drive_mult = getDriverMultiplier("OutMult"); + portConnect(muxf, "Y", "OutTemp"); + getNet("OutTemp")->addDownstreamNode(drive_mult); + for (unsigned int n = 0; n < number_bits; ++n) + drive_mult->addDownstreamNode(getNet("Out", makeNetIndex(n))); + } + + //Add area, power, and event results for each mux + addSubInstances(mux0, number_bits); + addElectricalSubResults(mux0, number_bits); + addSubInstances(mux1, number_bits); + addElectricalSubResults(mux1, number_bits); + addSubInstances(muxf, number_bits); + addElectricalSubResults(muxf, number_bits); + getEventResult("Mux")->addSubResult(mux0->getEventResult("Mux"), mux0_name, number_bits); + getEventResult("Mux")->addSubResult(mux1->getEventResult("Mux"), mux1_name, number_bits); + getEventResult("Mux")->addSubResult(muxf->getEventResult("MUX2"), muxf_name, number_bits); + + } + + } + else + { + //Instantiate a bunch of 1-bit multiplexers + for (unsigned int n = 0; n < number_bits; ++n) + { + String mux_name = "Mux_bit" + (String) n; + + Multiplexer* mux = new Multiplexer(mux_name, getTechModel()); + mux->setParameter("NumberInputs", number_inputs); + mux->setParameter("NumberBits", 1); + mux->setParameter("BitDuplicate", "TRUE"); + mux->construct(); + + // Connect inputs + for (unsigned int i = 0; i < number_inputs; ++i) + portConnect(mux, "In" + (String) i, "In" + (String) i, makeNetIndex(n)); + for(unsigned int i = 0; i < number_selects; ++i) + portConnect(mux, "Sel" + (String)i, "Sel" + (String)i); + portConnect(mux, "Out", "Out", makeNetIndex(n)); + + //Add area, power, and event results for each mux + addSubInstances(mux, 1.0); + addElectricalSubResults(mux, 1.0); + getEventResult("Mux")->addSubResult(mux->getEventResult("Mux"), mux_name, 1.0); + } + } + + return; + } + + void Multiplexer::propagateTransitionInfo() + { + // The only thing can be updated are the input probabilities...so we will update them + unsigned int number_bits = (unsigned int) getParameter("NumberBits"); + unsigned int number_inputs = (unsigned int) getParameter("NumberInputs"); + unsigned int number_selects = (unsigned int) ceil(log2((double) number_inputs)); + bool bit_duplicate = (bool) getParameter("BitDuplicate"); + bool is_top_level = getParameter("IsTopLevel").toBool(); + + //Number of inputs on the 0 side + unsigned int inputs_0 = (unsigned int) ceil((double) number_inputs / 2.0); + unsigned int selects_0 = (unsigned int) ceil(log2((double) inputs_0)); + + //Number of inputs on the 1 side + unsigned int inputs_1 = (unsigned int) floor((double) number_inputs / 2.0); + unsigned int selects_1 = (unsigned int) ceil(log2((double) inputs_1)); + + if (bit_duplicate || number_bits == 1) + { + if (number_inputs == 1) + { + //If theres only 1 input, output transition = input transition + propagatePortTransitionInfo("Out", "In0"); + } + else + { + // Update sub muxes with appropriate probabilities + ElectricalModel* mux0 = (ElectricalModel*)getSubInstance("Mux_way0"); + for(unsigned int i = 0; i < inputs_0; ++i) + { + propagatePortTransitionInfo(mux0, "In" + (String)i, "In" + (String)i); + } + for(unsigned int i = 0; i < selects_0; ++i) + { + propagatePortTransitionInfo(mux0, "Sel" + (String)i, "Sel" + (String)i); + } + mux0->use(); + ElectricalModel* mux1 = (ElectricalModel*)getSubInstance("Mux_way1"); + for(unsigned int i = 0; i < inputs_1; ++i) + { + propagatePortTransitionInfo(mux1, "In" + (String)i, "In" + (String)(i + inputs_0)); + } + for(unsigned int i = 0; i < selects_1; ++i) + { + propagatePortTransitionInfo(mux1, "Sel" + (String)i, "Sel" + (String)i); + } + mux1->use(); + ElectricalModel* muxf = (ElectricalModel*)getSubInstance("Mux2_i" + (String)number_inputs); + propagatePortTransitionInfo(muxf, "A", mux0, "Out"); + propagatePortTransitionInfo(muxf, "B", mux1, "Out"); + propagatePortTransitionInfo(muxf, "S0", "Sel" + (String)(number_selects-1)); + muxf->use(); + + // TODO hack + if(is_top_level) + { + for(unsigned int i = 0; i < number_selects; ++i) + { + ElectricalModel* selinv0 = (ElectricalModel*)getSubInstance(String::format("Sel%dInv0", i)); + ElectricalModel* selinv1 = (ElectricalModel*)getSubInstance(String::format("Sel%dInv1", i)); + propagatePortTransitionInfo(selinv0, "A", "Sel" + (String)i); + selinv0->use(); + propagatePortTransitionInfo(selinv1, "A", selinv0, "Y"); + selinv1->use(); + } + } + + // Set output transition + propagatePortTransitionInfo("Out", muxf, "Y"); + } + } + else + { + // Go through each bit and set the appropriate probability + for (unsigned int n = 0; n < number_bits; ++n) + { + ElectricalModel* mux_bit = (ElectricalModel*)getSubInstance("Mux_bit" + (String) n); + for(unsigned int i = 0; i < number_inputs; ++i) + { + propagatePortTransitionInfo(mux_bit, "In" + (String)i, "In" + (String)i); + } + for(unsigned int i = 0; i < number_selects; ++i) + { + propagatePortTransitionInfo(mux_bit, "Sel" + (String)i, "Sel" + (String)i); + } + mux_bit->use(); + } + + // Set output probability to be average that of probabilties of each output bit + ElectricalModel* mux_bit = (ElectricalModel*)getSubInstance("Mux_bit0"); + propagatePortTransitionInfo("Out", mux_bit, "Out"); + } + return; + } + +} // namespace DSENT + diff --git a/ext/dsent/model/electrical/Multiplexer.h b/ext/dsent/model/electrical/Multiplexer.h new file mode 100644 index 000000000..845798b18 --- /dev/null +++ b/ext/dsent/model/electrical/Multiplexer.h @@ -0,0 +1,34 @@ +#ifndef __DSENT_MODEL_ELECTRICAL_MULTIPLEXER_H__ +#define __DSENT_MODEL_ELECTRICAL_MULTIPLEXER_H__ + +#include "util/CommonType.h" +#include "model/ElectricalModel.h" + +namespace DSENT +{ + // A model of an N-to-1 multiplexer + class Multiplexer : public ElectricalModel + { + public: + Multiplexer(const String& instance_name_, const TechModel* tech_model_); + virtual ~Multiplexer(); + + public: + // Set a list of properties' name needed to construct model + void initParameters(); + // Set a list of properties' name needed to construct model + void initProperties(); + + // Clone and return a new instance + virtual Multiplexer* clone() const; + + protected: + // Build the model + virtual void constructModel(); + virtual void propagateTransitionInfo(); + + }; // class Multiplexer +} // namespace DSENT + +#endif // __DSENT_MODEL_ELECTRICAL_MULTIPLEXER_H__ + diff --git a/ext/dsent/model/electrical/MultiplexerCrossbar.cc b/ext/dsent/model/electrical/MultiplexerCrossbar.cc new file mode 100644 index 000000000..7400d5ed2 --- /dev/null +++ b/ext/dsent/model/electrical/MultiplexerCrossbar.cc @@ -0,0 +1,214 @@ +#include "model/electrical/MultiplexerCrossbar.h" + +#include <vector> +#include <cmath> + +#include "model/PortInfo.h" +#include "model/EventInfo.h" +#include "model/TransitionInfo.h" +#include "model/timing_graph/ElectricalNet.h" +#include "model/electrical/Multiplexer.h" + +namespace DSENT +{ + using std::ceil; + using std::vector; + + MultiplexerCrossbar::MultiplexerCrossbar(const String& instance_name_, const TechModel* tech_model_) + : ElectricalModel(instance_name_, tech_model_) + { + initParameters(); + initProperties(); + } + + MultiplexerCrossbar::~MultiplexerCrossbar() + {} + + void MultiplexerCrossbar::initParameters() + { + addParameterName("NumberInputs"); + addParameterName("NumberOutputs"); + addParameterName("NumberBits"); + addParameterName("BitDuplicate", "TRUE"); + return; + } + + void MultiplexerCrossbar::initProperties() + { + return; + } + + MultiplexerCrossbar* MultiplexerCrossbar::clone() const + { + // TODO + return NULL; + } + + void MultiplexerCrossbar::constructModel() + { + // Get Parameters + unsigned int number_inputs = getParameter("NumberInputs").toUInt(); + unsigned int number_outputs = getParameter("NumberOutputs").toUInt(); + unsigned int number_bits = getParameter("NumberBits").toUInt(); + bool bit_duplicate = getParameter("BitDuplicate").toBool(); + + ASSERT(number_inputs > 0, "[Error] " + getInstanceName() + " -> Number of inputs must be > 0!"); + ASSERT(number_outputs > 0, "[Error] " + getInstanceName() + " -> Number of outputs must be > 0!"); + ASSERT(number_bits > 0, "[Error] " + getInstanceName() + " -> Number of bits must be > 0!"); + + unsigned int number_selects = (unsigned int)ceil(log2((double)number_inputs)); + getGenProperties()->set("NumberSelectsPerPort", number_selects); + + // Construct electrical ports and nets + // Create input ports + for(unsigned int i = 0; i < number_inputs; ++i) + { + createInputPort("In" + (String)i, makeNetIndex(0, number_bits-1)); + } + // Create select signals + for(unsigned int i = 0; i < number_outputs; ++i) + { + for(unsigned int j = 0; j < number_selects; ++j) + { + createInputPort(String::format("Sel%d_%d", i, j)); + } + } + // Create output ports + for(unsigned int i = 0; i < number_outputs; ++i) + { + createOutputPort("Out" + (String)i, makeNetIndex(0, number_bits-1)); + } + + // Create energy, power, and area results + addAreaResult(new AtomicResult("CrossbarWire")); + addAreaResult(new AtomicResult("CrossbarFill")); + createElectricalResults(); + getEventInfo("Idle")->setStaticTransitionInfos(); + createElectricalEventResult("Multicast0"); + getEventInfo("Multicast0")->setStaticTransitionInfos(); + for(unsigned int i = 1; i <= number_outputs; ++i) + { + createElectricalEventResult("Multicast" + (String)i); + EventInfo* event_info = getEventInfo("Multicast" + (String)i); + // Assuming that In0 is sending to Out0, Out1, ..., Outi + // and other input ports are static + for(unsigned int j = 1; j < number_inputs; ++j) + { + event_info->setStaticTransitionInfo("In" + (String)j); + } + for(unsigned int j = i; j < number_outputs; ++j) + { + for(unsigned int k = 0; k < number_selects; ++k) + { + event_info->setStaticTransitionInfo(String::format("Sel%d_%d", j, k)); + } + } + } + createElectricalEventResult("Crossbar"); + + // Initiate multiplexers + vector<String> mux_names(number_outputs, ""); + vector<Multiplexer*> muxs(number_outputs, NULL); + for(unsigned int i = 0; i < number_outputs; ++i) + { + mux_names[i] = "Mux" + (String)i; + muxs[i] = new Multiplexer(mux_names[i], getTechModel()); + muxs[i]->setParameter("NumberInputs", number_inputs); + muxs[i]->setParameter("NumberBits", number_bits); + muxs[i]->setParameter("BitDuplicate", bit_duplicate); + muxs[i]->construct(); + } + + // Connect inputs and outputs to multiplexers + for(unsigned int i = 0; i < number_outputs; ++i) + { + // Connect inputs + for(unsigned int j = 0; j < number_inputs; ++j) + { + portConnect(muxs[i], "In" + (String)j, "In" + (String)j, makeNetIndex(0, number_bits-1)); + } + + // Connect select signals + for(unsigned int j = 0; j < number_selects; ++j) + { + portConnect(muxs[i], "Sel" + (String)j, String::format("Sel%d_%d", i, j)); + } + + // Connect outputs + portConnect(muxs[i], "Out", "Out" + (String)i, makeNetIndex(0, number_bits-1)); + } + + // Add area, power, and event results for each mux + for(unsigned int i = 0; i < number_outputs; ++i) + { + addSubInstances(muxs[i], 1.0); + addElectricalSubResults(muxs[i], 1.0); + for(unsigned int j = 0; j <= number_outputs; ++j) + { + getEventResult("Multicast" + (String)j)->addSubResult(muxs[i]->getEventResult("Mux"), mux_names[i], 1.0); + } + getEventResult("Crossbar")->addSubResult(muxs[i]->getEventResult("Mux"), mux_names[i], 1.0); + } + + // Estimate wiring area + const String& crossbar_wire_layer = "Intermediate"; + addElectricalWireSubResult(crossbar_wire_layer, getAreaResult("CrossbarWire"), "Self", 1.0); + double wire_width = getTechModel()->get("Wire->" + crossbar_wire_layer + "->MinWidth").toDouble(); + double wire_spacing = getTechModel()->get("Wire->" + crossbar_wire_layer + "->MinSpacing").toDouble(); + double wire_pitch = wire_width + wire_spacing; + double wire_area = (number_bits * number_inputs * wire_pitch) * (number_bits * number_outputs * wire_pitch); + getAreaResult("CrossbarWire")->setValue(wire_area); + + // Add filler area + getAreaResult("Active")->addSubResult(getAreaResult("CrossbarFill"), "Self", 1.0); + return; + } + + void MultiplexerCrossbar::updateModel() + { + // Update all sub instances + Model::updateModel(); + + // Update filler area + // Total Active area = max(stdcell active area, wiring area); + double wire_area = getAreaResult("CrossbarWire")->calculateSum(); + double active_area = getAreaResult("Active")->calculateSum(); + double fill_area = 0.0; + if(active_area < wire_area) + { + fill_area = wire_area - active_area; + } + getAreaResult("CrossbarFill")->setValue(fill_area); + return; + } + + void MultiplexerCrossbar::propagateTransitionInfo() + { + // The only thing can be updated are the input probabilities + const unsigned int number_inputs = getParameter("NumberInputs").toUInt(); + const unsigned int number_outputs = getParameter("NumberOutputs").toUInt(); + + const unsigned int number_selects = getGenProperties()->get("NumberSelectsPerPort").toUInt(); + + for(unsigned int i = 0; i < number_outputs; ++i) + { + ElectricalModel* muxi = (ElectricalModel*)getSubInstance("Mux" + (String)i); + for(unsigned int j = 0; j < number_inputs; ++j) + { + propagatePortTransitionInfo(muxi, "In" + (String)j, "In" + (String)j); + } + for(unsigned int j = 0; j < number_selects; ++j) + { + propagatePortTransitionInfo(muxi, "Sel" + (String)j, String::format("Sel%d_%d", i, j)); + } + muxi->use(); + + // Set output probability + propagatePortTransitionInfo("Out" + (String)i, muxi, "Out"); + } + + return; + } + +} // namespace DSENT + diff --git a/ext/dsent/model/electrical/MultiplexerCrossbar.h b/ext/dsent/model/electrical/MultiplexerCrossbar.h new file mode 100644 index 000000000..e7f092061 --- /dev/null +++ b/ext/dsent/model/electrical/MultiplexerCrossbar.h @@ -0,0 +1,38 @@ +#ifndef __DSENT_MODEL_ELECTRICAL_MULTIPLEXER_CROSSBAR_H__ +#define __DSENT_MODEL_ELECTRICAL_MULTIPLEXER_CROSSBAR_H__ + +#include "util/CommonType.h" +#include "model/ElectricalModel.h" + +namespace DSENT +{ + // A model for a NxM W-bit multiplexer-based crossbar + class MultiplexerCrossbar : public ElectricalModel + { + public: + MultiplexerCrossbar(const String& instance_name_, const TechModel* tech_model_); + virtual ~MultiplexerCrossbar(); + + public: + // Set a list of paramerters' name needed to construct model + void initParameters(); + // Set a list of peroperties' name needed to construct model + void initProperties(); + + // Clone and return a new instance + virtual MultiplexerCrossbar* clone() const; + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void propagateTransitionInfo(); + + private: + // Disable copy constructor + MultiplexerCrossbar(const MultiplexerCrossbar& crossbar_); + }; // class MultiplexerCrossbar +} // namespace DSENT + +#endif // __DSENT_MODEL_ELECTRICAL_MULTIPLEXER_CROSSBAR_H__ + diff --git a/ext/dsent/model/electrical/MuxTreeSerializer.cc b/ext/dsent/model/electrical/MuxTreeSerializer.cc new file mode 100644 index 000000000..8f3b92122 --- /dev/null +++ b/ext/dsent/model/electrical/MuxTreeSerializer.cc @@ -0,0 +1,226 @@ +#include "model/electrical/MuxTreeSerializer.h" + +#include <cmath> + +#include "model/PortInfo.h" +#include "model/TransitionInfo.h" +#include "model/EventInfo.h" +#include "model/std_cells/StdCellLib.h" +#include "model/std_cells/StdCell.h" +#include "model/electrical/Multiplexer.h" +#include "model/timing_graph/ElectricalNet.h" + +namespace DSENT +{ + using std::ceil; + + MuxTreeSerializer::MuxTreeSerializer(const String& instance_name_, const TechModel* tech_model_) + : ElectricalModel(instance_name_, tech_model_) + { + initParameters(); + initProperties(); + } + + MuxTreeSerializer::~MuxTreeSerializer() + {} + + void MuxTreeSerializer::initParameters() + { + addParameterName("InDataRate"); + addParameterName("OutDataRate"); + addParameterName("InBits"); //Output width will just be input width / serialization ratio + } + + void MuxTreeSerializer::initProperties() + { + return; + } + + MuxTreeSerializer* MuxTreeSerializer::clone() const + { + // TODO + return NULL; + } + + void MuxTreeSerializer::constructModel() + { + // Get parameters + double in_data_rate = getParameter("InDataRate").toDouble(); + double out_data_rate = getParameter("OutDataRate").toDouble(); + unsigned int in_bits = getParameter("InBits").toUInt(); + + // Calculate serialization ratio + unsigned int serialization_ratio = (unsigned int) floor(out_data_rate / in_data_rate); + ASSERT(serialization_ratio == out_data_rate / in_data_rate, + "[Error] " + getInstanceName() + " -> Cannot have non-integer serialization ratios " + + "(" + (String) (in_data_rate / out_data_rate) + ")!"); + + // Calculate output width + ASSERT(floor((double) in_bits / serialization_ratio) == (double) in_bits / serialization_ratio, + "[Error] " + getInstanceName() + " -> Input width (" + (String) in_bits + ") " + + "must be a multiple of the serialization ratio (" + (String) serialization_ratio + ")!"); + unsigned int output_bits = in_bits / serialization_ratio; + + // Calculate the number of multiplexer stages + unsigned int number_stages = (unsigned int)ceil(log2((double) serialization_ratio)); + + // Store calculated values + getGenProperties()->set("SerializationRatio", serialization_ratio); + getGenProperties()->set("OutputBits", output_bits); + getGenProperties()->set("NumberStages", number_stages); + + // Create ports + createInputPort("In", makeNetIndex(0, in_bits-1)); + createInputPort("OutCK"); + createOutputPort("Out", makeNetIndex(0, output_bits-1)); + + //Create energy, power, and area results + createElectricalResults(); + createElectricalEventResult("Serialize"); + getEventInfo("Serialize")->setTransitionInfo("OutCK", TransitionInfo(0.0, (double) serialization_ratio / 2.0, 0.0)); + //Set conditions during idle state + getEventInfo("Idle")->setStaticTransitionInfos(); + getEventInfo("Idle")->setTransitionInfo("OutCK", TransitionInfo(0.0, (double) serialization_ratio / 2.0, 0.0)); + + // Mark OutCK as a false path (since timing tool will do strange stuff due to all the clock divides and stuff) + getNet("OutCK")->setFalsePath(true); + + // Create mux-tree instance + if (serialization_ratio == 1) + { + // No need to do anything, hohoho + assign("Out", "In"); + } + else + { + // Create multiplexer + String mux_tree_name = "MuxTree"; + ElectricalModel* mux_tree = new Multiplexer(mux_tree_name, getTechModel()); + mux_tree->setParameter("NumberInputs", serialization_ratio); + mux_tree->setParameter("NumberBits", output_bits); + mux_tree->setParameter("BitDuplicate", "TRUE"); + mux_tree->construct(); + // Create nets + if (number_stages > 1) + createNet("MuxSel_b", makeNetIndex(0, number_stages-2)); + createNet("MuxSel", makeNetIndex(0, number_stages-1)); + assign("MuxSel", makeNetIndex(number_stages-1), "OutCK"); + // Create reindexed net (to help out with indexing) + createNet("InTmp", makeNetIndex(0, in_bits-1)); + for (unsigned int i = 0; i < serialization_ratio; ++i) + for (unsigned int j = 0; j < output_bits; ++j) + assign("InTmp", makeNetIndex(i*output_bits+j), "In", makeNetIndex(j*serialization_ratio+i)); + + // Connect ports + for (unsigned int i = 0; i < serialization_ratio; ++i) + portConnect(mux_tree, "In" + (String) i, "InTmp", makeNetIndex(i*output_bits, (i+1)*output_bits-1)); + + for (unsigned int i = 0; i < number_stages; ++i) + portConnect(mux_tree, "Sel" + (String) i, "MuxSel", makeNetIndex(i)); + portConnect(mux_tree, "Out", "Out"); + + // Add subinstance and events + addSubInstances(mux_tree, 1.0); + addElectricalSubResults(mux_tree, 1.0); + // Add serialize event/power + getEventResult("Serialize")->addSubResult(mux_tree->getEventResult("Mux"), mux_tree_name, 1.0); + + // Create clock dividers (assumes power of 2...), don't need divider for fastest output stage + for (unsigned int i = 0; i < number_stages - 1; ++i) + { + // Clk dividing registers + const String& clk_div_dff_name = "ClkDivDFF_" + (String) i; + StdCell* clk_div_dff = getTechModel()->getStdCellLib()->createStdCell("DFFQ", clk_div_dff_name); + clk_div_dff->construct(); + portConnect(clk_div_dff, "D", "MuxSel_b", makeNetIndex(i)); + portConnect(clk_div_dff, "Q", "MuxSel", makeNetIndex(i)); + portConnect(clk_div_dff, "CK", "MuxSel", makeNetIndex(i+1)); + addSubInstances(clk_div_dff, 1.0); + addElectricalSubResults(clk_div_dff, 1.0); + + // Inversions + const String& clk_div_inv_name = "ClkDivINV_" + (String) i; + StdCell* clk_div_inv = getTechModel()->getStdCellLib()->createStdCell("INV", clk_div_inv_name); + clk_div_inv->construct(); + portConnect(clk_div_inv, "A", "MuxSel", makeNetIndex(i)); + portConnect(clk_div_inv, "Y", "MuxSel_b", makeNetIndex(i)); + addSubInstances(clk_div_inv, 1.0); + addElectricalSubResults(clk_div_inv, 1.0); + + getEventResult("Serialize")->addSubResult(clk_div_dff->getEventResult("CK"), clk_div_dff_name, 1.0); + getEventResult("Serialize")->addSubResult(clk_div_dff->getEventResult("DFFD"), clk_div_dff_name, 1.0); + getEventResult("Serialize")->addSubResult(clk_div_dff->getEventResult("DFFQ"), clk_div_dff_name, 1.0); + getEventResult("Serialize")->addSubResult(clk_div_inv->getEventResult("INV"), clk_div_inv_name, 1.0); + } + } + + return; + } + + void MuxTreeSerializer::propagateTransitionInfo() + { + // Get some generated properties + const unsigned int serialization_ratio = getGenProperties()->get("SerializationRatio"); + const unsigned int number_stages = getGenProperties()->get("NumberStages"); + + // Set transition info of the mux tree and clock divide DFF + if (serialization_ratio == 1) + { + // If no serialization, then just propagate input transition info to output port + propagatePortTransitionInfo("Out", "In"); + } + else + { + + // Propagate transition probabilities to the mux tree + ElectricalModel* mux_tree = (ElectricalModel*) getSubInstance("MuxTree"); + // All input ports of the mux have the same probability + for (unsigned int i = 0; i < serialization_ratio; ++i) + propagatePortTransitionInfo(mux_tree, "In" + (String) i, "In"); + // Connect last stage of the mux + propagatePortTransitionInfo(mux_tree, "Sel" + (String) (number_stages - 1), "OutCK"); + // Keep track of the last clock divider + ElectricalModel* last_clk_div_dff = NULL; + // Find P01 of OutCK + double last_P01_CK = getInputPort("OutCK")->getTransitionInfo().getNumberTransitions01(); + // Start from the last stage (since it is the stage with no clock division) + for (unsigned int i = 0; i < number_stages - 1; ++i) + { + const String& clk_div_dff_name = "ClkDivDFF_" + (String) (number_stages - i - 2); + const String& clk_div_inv_name = "ClkDivINV_" + (String) (number_stages - i - 2); + + ElectricalModel* clk_div_dff = (ElectricalModel*) getSubInstance(clk_div_dff_name); + if (last_clk_div_dff == NULL) + propagatePortTransitionInfo(clk_div_dff, "CK", "OutCK"); + else + propagatePortTransitionInfo(clk_div_dff, "CK", last_clk_div_dff, "Q"); + // Since it is a clock divider, P01 is D and Q are simply half the P01 of D and Q of + // the input clock + if (last_P01_CK != 0) clk_div_dff->getInputPort("D")->setTransitionInfo(TransitionInfo(0.0, last_P01_CK * 0.5, 0.0)); + else clk_div_dff->getInputPort("D")->setTransitionInfo(TransitionInfo(0.5, 0.0, 0.5)); + + clk_div_dff->use(); + + ElectricalModel* clk_div_inv = (ElectricalModel*) getSubInstance(clk_div_inv_name); + propagatePortTransitionInfo(clk_div_inv, "A", clk_div_dff, "Q"); + clk_div_inv->use(); + + // Connect select port of the mux + propagatePortTransitionInfo(mux_tree, "Sel" + (String) (number_stages - i - 2), clk_div_dff, "Q"); + + // Clk divide by 2; + last_P01_CK = last_P01_CK * 0.5; + // Remember the last clk div DFF + last_clk_div_dff = clk_div_dff; + } + + mux_tree->use(); + // Set output transition info to be the output transition info of the mux tree + propagatePortTransitionInfo("Out", mux_tree, "Out"); + } + + return; + } + +} // namespace DSENT + diff --git a/ext/dsent/model/electrical/MuxTreeSerializer.h b/ext/dsent/model/electrical/MuxTreeSerializer.h new file mode 100644 index 000000000..f56cccc4f --- /dev/null +++ b/ext/dsent/model/electrical/MuxTreeSerializer.h @@ -0,0 +1,33 @@ +#ifndef __DSENT_MODEL_ELECTRICAL_MUXTREESERIALIZER_H__ +#define __DSENT_MODEL_ELECTRICAL_MUXTREESERIALIZER_H__ + +#include "util/CommonType.h" +#include "model/ElectricalModel.h" + +namespace DSENT +{ + class MuxTreeSerializer : public ElectricalModel + { + public: + MuxTreeSerializer(const String& instance_name_, const TechModel* tech_model_); + virtual ~MuxTreeSerializer(); + + public: + // Set a list of properties' name needed to construct model + void initParameters(); + // Set a list of properties' name needed to construct model + void initProperties(); + + // Clone and return a new instance + virtual MuxTreeSerializer* clone() const; + + protected: + // Build the model + virtual void constructModel(); + virtual void propagateTransitionInfo(); + + }; // class MuxTreeSerializer +} // namespace DSENT + +#endif // __DSENT_MODEL_ELECTRICAL_MUXTREESERIALIZER_H__ + diff --git a/ext/dsent/model/electrical/OR.cc b/ext/dsent/model/electrical/OR.cc new file mode 100644 index 000000000..d948ff086 --- /dev/null +++ b/ext/dsent/model/electrical/OR.cc @@ -0,0 +1,239 @@ +#include "model/electrical/OR.h" + +#include <cmath> + +#include "model/PortInfo.h" +#include "model/TransitionInfo.h" +#include "model/EventInfo.h" +#include "model/std_cells/StdCellLib.h" +#include "model/std_cells/StdCell.h" +#include "model/timing_graph/ElectricalNet.h" + +namespace DSENT +{ + using std::ceil; + using std::floor; + + OR::OR(const String& instance_name_, const TechModel* tech_model_) + : ElectricalModel(instance_name_, tech_model_) + { + initParameters(); + initProperties(); + } + + OR::~OR() + {} + + void OR::initParameters() + { + addParameterName("NumberInputs"); + addParameterName("NumberBits"); + addParameterName("BitDuplicate", "TRUE"); + return; + } + + void OR::initProperties() + { + return; + } + + OR* OR::clone() const + { + // TODO + return NULL; + } + + void OR::constructModel() + { + // Get parameter + unsigned int number_inputs = getParameter("NumberInputs").toUInt(); + unsigned int number_bits = getParameter("NumberBits").toUInt(); + bool bit_duplicate = getParameter("BitDuplicate").toBool(); + + ASSERT(number_inputs > 0, "[Error] " + getInstanceName() + + " -> Number of inputs must be > 0!"); + ASSERT(number_bits > 0, "[Error] " + getInstanceName() + + " -> Number of bits must be > 0!"); + + + // Init ports + for(unsigned int i = 0; i < number_inputs; ++i) + { + createInputPort("In" + (String)i, makeNetIndex(0, number_bits-1)); + } + createOutputPort("Out", makeNetIndex(0, number_bits-1)); + + // Number of inputs on the 0 side + unsigned int or0_number_inputs = (unsigned int)ceil((double)number_inputs / 2.0); + // Number of inputs on the 1 side + unsigned int or1_number_inputs = (unsigned int)floor((double)number_inputs / 2.0); + + // Create area, power, and event results + createElectricalResults(); + createElectricalEventResult("OR"); + + getEventInfo("Idle")->setStaticTransitionInfos(); + + //Depending on whether we want to create a 1-bit instance and have it multiplied + //up by number of bits or actually instantiate number_bits of 1-bit instances. + //Recursively instantiates smaller ors + if(bit_duplicate || number_bits == 1) + { + // If it is just a 1-input or, just connect output to input + if(number_inputs == 1) + { + assign("Out", "In0"); + } + else + { + // If it is more than 1 input, instantiate two sub ors (OR_way0 and OR_way1) + // and create a final OR2 to OR them + const String& or0_name = "OR_way0"; + const String& or1_name = "OR_way1"; + const String& orf_name = "OR2_i" + (String)number_inputs; + + OR* or0 = new OR(or0_name, getTechModel()); + or0->setParameter("NumberInputs", or0_number_inputs); + or0->setParameter("NumberBits", 1); + or0->setParameter("BitDuplicate", "TRUE"); + or0->construct(); + + OR* or1 = new OR(or1_name, getTechModel()); + or1->setParameter("NumberInputs", or1_number_inputs); + or1->setParameter("NumberBits", 1); + or1->setParameter("BitDuplicate", "TRUE"); + or1->construct(); + + StdCell* orf = getTechModel()->getStdCellLib()->createStdCell("OR2", orf_name); + orf->construct(); + + // Create outputs of way0 and way1 ors with final or + createNet("way0_Out"); + createNet("way1_Out"); + portConnect(or0, "Out", "way0_Out"); + portConnect(or1, "Out", "way1_Out"); + portConnect(orf, "A", "way0_Out"); + portConnect(orf, "B", "way1_Out"); + + // Connect inputs to the sub ors. + for(unsigned int i = 0; i < or0_number_inputs; ++i) + { + createNet("way0_In" + (String)i); + portConnect(or0, "In" + (String)i, "way0_In" + (String)i); + assignVirtualFanin("way0_In" + (String)i, "In" + (String)i); + } + for(unsigned int i = 0; i < or1_number_inputs; ++i) + { + createNet("way1_In" + (String)i); + portConnect(or1, "In" + (String)i, "way1_In" + (String)i); + assignVirtualFanin("way1_In" + (String)i, "In" + (String)(i + or0_number_inputs)); + } + + // Connect outputs + createNet("OR2_Out"); + portConnect(orf, "Y", "OR2_Out"); + assignVirtualFanout("Out", "OR2_Out"); + + addSubInstances(or0, number_bits); + addElectricalSubResults(or0, number_bits); + addSubInstances(or1, number_bits); + addElectricalSubResults(or1, number_bits); + addSubInstances(orf, number_bits); + addElectricalSubResults(orf, number_bits); + + Result* or_event = getEventResult("OR"); + or_event->addSubResult(or0->getEventResult("OR"), or0_name, number_bits); + or_event->addSubResult(or1->getEventResult("OR"), or1_name, number_bits); + or_event->addSubResult(orf->getEventResult("OR2"), orf_name, number_bits); + + } + } + else + { + // Init a bunch of 1-bit ors + Result* or_event = getEventResult("OR"); + for(unsigned int n = 0; n < number_bits; ++n) + { + const String& or_name = "OR_bit" + (String)n; + + OR* ors = new OR(or_name, getTechModel()); + ors->setParameter("NumberInputs", number_inputs); + ors->setParameter("NumberBits", 1); + ors->setParameter("BitDuplicate", "TRUE"); + ors->construct(); + + for(unsigned int i = 0; i < number_inputs; ++i) + { + portConnect(ors, "In" + (String)i, "In" + (String)i, makeNetIndex(n)); + } + portConnect(ors, "Out", "Out", makeNetIndex(n)); + + addSubInstances(ors, 1.0); + addElectricalSubResults(ors, 1.0); + or_event->addSubResult(ors->getEventResult("OR"), or_name, 1.0); + } + } + return; + } + + void OR::propagateTransitionInfo() + { + // Get parameters + unsigned int number_inputs = getParameter("NumberInputs").toUInt(); + unsigned int number_bits = getParameter("NumberBits").toUInt(); + bool bit_duplicate = getParameter("BitDuplicate").toBool(); + + // Number of inputs on 0 side + unsigned int or0_number_inputs = (unsigned int)ceil((double)number_inputs / 2.0); + unsigned int or1_number_inputs = (unsigned int)floor((double)number_inputs / 2.0); + + if(bit_duplicate || number_bits == 1) + { + if(number_inputs == 1) + { + propagatePortTransitionInfo("Out", "In0"); + } + else + { + ElectricalModel* or0 = (ElectricalModel*)getSubInstance("OR_way0"); + for(unsigned int i = 0; i < or0_number_inputs; ++i) + { + propagatePortTransitionInfo(or0, "In" + (String)i, "In" + (String)i); + } + or0->use(); + + ElectricalModel* or1 = (ElectricalModel*)getSubInstance("OR_way1"); + for(unsigned int i = 0; i < or1_number_inputs; ++i) + { + propagatePortTransitionInfo(or1, "In" + (String)i, "In" + (String)i); + } + or1->use(); + + ElectricalModel* orf = (ElectricalModel*)getSubInstance("OR2_i" + (String)number_inputs); + propagatePortTransitionInfo(orf, "A", or0, "Out"); + propagatePortTransitionInfo(orf, "B", or1, "Out"); + orf->use(); + + // Set output probability + propagatePortTransitionInfo("Out", orf, "Y"); + } + } + else + { + for(unsigned int n = 0; n < number_bits; ++n) + { + ElectricalModel* or_bit = (ElectricalModel*)getSubInstance("OR_bit" + (String)n); + for(unsigned int i = 0; i < number_inputs; ++i) + { + propagatePortTransitionInfo(or_bit, "In" + (String)i, "In" + (String)i); + } + or_bit->use(); + } + + ElectricalModel* or_bit = (ElectricalModel*)getSubInstance("OR_bit0"); + propagatePortTransitionInfo("Out", or_bit, "Out"); + } + return; + } +} // namespace DSENT + diff --git a/ext/dsent/model/electrical/OR.h b/ext/dsent/model/electrical/OR.h new file mode 100644 index 000000000..b8304799c --- /dev/null +++ b/ext/dsent/model/electrical/OR.h @@ -0,0 +1,36 @@ +#ifndef __DSENT_MODEL_ELECTRICAL_OR_H__ +#define __DSENT_MODEL_ELECTRICAL_OR_H__ + +#include "util/CommonType.h" +#include "model/ElectricalModel.h" + +namespace DSENT +{ + /** + * \brief A class that implements a n-input OR gate + */ + class OR : public ElectricalModel + { + public: + OR(const String& instance_name_, const TechModel* tech_model_); + virtual ~OR(); + + public: + // Set a list of properties' name needed to construct model + void initParameters(); + // Set a list of properties' name needed to construct model + void initProperties(); + + // Clone and return a new instance + virtual OR* clone() const; + + protected: + // Build the model + virtual void constructModel(); + virtual void propagateTransitionInfo(); + + }; // class OR +} // namespace DSENT + +#endif // __DSENT_MODEL_ELECTRICAL_OR_H__ + diff --git a/ext/dsent/model/electrical/RepeatedLink.cc b/ext/dsent/model/electrical/RepeatedLink.cc new file mode 100644 index 000000000..08a40e432 --- /dev/null +++ b/ext/dsent/model/electrical/RepeatedLink.cc @@ -0,0 +1,305 @@ +#include "model/electrical/RepeatedLink.h" + +#include "model/PortInfo.h" +#include "model/EventInfo.h" +#include "model/TransitionInfo.h" +#include "model/std_cells/StdCellLib.h" +#include "model/std_cells/StdCell.h" +#include "model/timing_graph/ElectricalTimingTree.h" +#include "model/timing_graph/ElectricalTimingNode.h" +#include "model/timing_graph/ElectricalNet.h" +#include "model/timing_graph/ElectricalDriver.h" +#include "model/timing_graph/ElectricalDelay.h" +#include "model/timing_graph/ElectricalLoad.h" + +namespace DSENT +{ + RepeatedLink::RepeatedLink(const String& instance_name_, const TechModel* tech_model_) + : ElectricalModel(instance_name_, tech_model_) + { + m_repeater_ = NULL; + m_repeater_load_ = NULL; + m_timing_tree_ = NULL; + + initParameters(); + initProperties(); + } + + RepeatedLink::~RepeatedLink() + { + delete m_repeater_; + delete m_repeater_load_; + delete m_timing_tree_; + } + + void RepeatedLink::initParameters() + { + addParameterName("NumberBits"); + addParameterName("WireLayer"); + addParameterName("WireWidthMultiplier", 1.0); + addParameterName("WireSpacingMultiplier", 1.0); + return; + } + + void RepeatedLink::initProperties() + { + addPropertyName("WireLength"); + addPropertyName("Delay"); + addPropertyName("IsKeepParity", "TRUE"); + return; + } + + RepeatedLink* RepeatedLink::clone() const + { + // TODO + return NULL; + } + + void RepeatedLink::constructModel() + { + // Get parameters + unsigned int number_bits = getParameter("NumberBits").toUInt(); + const String& wire_layer = getParameter("WireLayer"); + double wire_width_multiplier = getParameter("WireWidthMultiplier").toDouble(); + double wire_spacing_multiplier = getParameter("WireSpacingMultiplier").toDouble(); + + ASSERT(number_bits > 0, "[Error] " + getInstanceName() + + " -> Number of bits must be > 0!"); + ASSERT(getTechModel()->isWireLayerExist(wire_layer), "[Error] " + getInstanceName() + + " -> Wire layer does not exist!"); + ASSERT(wire_width_multiplier >= 1.0, "[Error] " + getInstanceName() + + " -> Wire width multiplier must be >= 1.0!"); + ASSERT(wire_spacing_multiplier >= 1.0, "[Error] " + getInstanceName() + + " -> Wire spacing multiplier must be >= 1.0!"); + + double wire_min_width = getTechModel()->get("Wire->" + wire_layer + "->MinWidth").toDouble(); + double wire_min_spacing = getTechModel()->get("Wire->" + wire_layer + "->MinSpacing").toDouble(); + + double wire_width = wire_min_width * wire_width_multiplier; + double wire_spacing = wire_min_spacing * wire_spacing_multiplier; + + double wire_cap_per_len = getTechModel()->calculateWireCapacitance(wire_layer, wire_width, wire_spacing, 1.0); + double wire_res_per_len = getTechModel()->calculateWireResistance(wire_layer, wire_width, 1.0); + + getGenProperties()->set("WireWidth", wire_width); + getGenProperties()->set("WireSpacing", wire_spacing); + getGenProperties()->set("WireCapacitancePerLength", wire_cap_per_len); + getGenProperties()->set("WireResistancePerLength", wire_res_per_len); + + // Create ports + createInputPort("In", makeNetIndex(0, number_bits-1)); + createOutputPort("Out", makeNetIndex(0, number_bits-1)); + + // Create area, power, and event results + createElectricalAtomicResults(); + createElectricalEventAtomicResult("Send"); + + // Create connections + // Since the length is not set yet, we only to virtual fan-in and virtual fan-out + createNet("InTmp"); + createNet("OutTmp"); + assignVirtualFanin("InTmp", "In"); + assignVirtualFanout("Out", "OutTmp"); + + // Build Electrical Connectivity + createLoad("In_Cap"); + createDelay("In_to_Out_delay"); + createDriver("Out_Ron", false); // Indicate this driver is not sizable + + ElectricalLoad* in_cap = getLoad("In_Cap"); + ElectricalDelay* in_to_out_delay = getDelay("In_to_Out_delay"); + ElectricalDriver* out_ron = getDriver("Out_Ron"); + + getNet("InTmp")->addDownstreamNode(in_cap); + in_cap->addDownstreamNode(in_to_out_delay); + in_to_out_delay->addDownstreamNode(out_ron); + out_ron->addDownstreamNode(getNet("OutTmp")); + + // Init a repeater and a load to mimic a segment of a repeated link + m_repeater_ = getTechModel()->getStdCellLib()->createStdCell("INV", "Repeater"); + m_repeater_->construct(); + m_repeater_load_ = new ElectricalLoad("RepeaterIn_Cap", this); + // Make path repeater_ -> repeater_load_ + // to catch the repeater's input/output cap and ensure only one inverter delay + // is added + m_repeater_->getNet("Y")->addDownstreamNode(m_repeater_load_); + // Init a timing object to calculate delay + m_timing_tree_ = new ElectricalTimingTree("RepeatedLink", this); + m_timing_tree_->performCritPathExtract(m_repeater_->getNet("A")); + return; + } + + void RepeatedLink::updateModel() + { + unsigned int number_bits = getParameter("NumberBits").toUInt(); + + // Get properties + double wire_length = getProperty("WireLength").toDouble(); + double required_delay = getProperty("Delay").toDouble(); + bool isKeepParity = getProperty("IsKeepParity").toBool(); + + ASSERT(wire_length >= 0, "[Error] " + getInstanceName() + + " -> Wire length must be >= 0!"); + ASSERT(required_delay >= 0, "[Error] " + getInstanceName() + + " -> Required delay must be >= 0!"); + + const String& wire_layer = getParameter("WireLayer"); + double wire_width = getGenProperties()->get("WireWidth").toDouble(); + double wire_spacing = getGenProperties()->get("WireSpacing").toDouble(); + + // Calculate the total wire cap and total wire res + double wire_cap_per_len = getGenProperties()->get("WireCapacitancePerLength").toDouble(); + double wire_res_per_len = getGenProperties()->get("WireResistancePerLength").toDouble(); + double total_wire_cap = wire_cap_per_len * wire_length; + double total_wire_res = wire_res_per_len * wire_length; + + m_repeater_->update(); + + unsigned int increment_segments = (isKeepParity)? 2:1; + unsigned int number_segments = increment_segments; + double delay; + m_repeater_->setMinDrivingStrength(); + m_repeater_->getNet("Y")->setDistributedCap(total_wire_cap / number_segments); + m_repeater_->getNet("Y")->setDistributedRes(total_wire_res / number_segments); + m_repeater_load_->setLoadCap(m_repeater_->getNet("A")->getTotalDownstreamCap()); + m_timing_tree_->performCritPathExtract(m_repeater_->getNet("A")); + delay = m_timing_tree_->calculateCritPathDelay(m_repeater_->getNet("A")) * number_segments; + + // If everything is 0, use number_segments min-sized repeater + if(wire_length != 0) + { + // Set the initial number of segments based on isKeepParity + double last_min_size_delay = 0; + unsigned int iteration = 0; + + // First set the repeater to the minimum driving strength + last_min_size_delay = delay; + + Log::printLine(getInstanceName() + " -> Beginning Repeater Insertion"); + + while(required_delay < delay) + { + Log::printLine(getInstanceName() + " -> Repeater Insertion Iteration " + (String)iteration + + ": Required delay = " + (String)required_delay + + ", Delay = " + (String)delay + + ", Slack = " + (String)(required_delay - delay) + + ", Number of repeaters = " + (String)number_segments); + + // Size up if timing is not met + while(required_delay < delay) + { + if(m_repeater_->hasMaxDrivingStrength()) + { + break; + } + m_repeater_->increaseDrivingStrength(); + m_repeater_load_->setLoadCap(m_repeater_->getNet("A")->getTotalDownstreamCap()); + m_timing_tree_->performCritPathExtract(m_repeater_->getNet("A")); + delay = m_timing_tree_->calculateCritPathDelay(m_repeater_->getNet("A")) * number_segments; + + iteration++; + Log::printLine(getInstanceName() + " -> Slack: " + (String)(required_delay - delay)); + } + // Increase number of segments if timing is not met + if(required_delay < delay) + { + number_segments += increment_segments; + m_repeater_->setMinDrivingStrength(); + m_repeater_->getNet("Y")->setDistributedCap(total_wire_cap / number_segments); + m_repeater_->getNet("Y")->setDistributedRes(total_wire_res / number_segments); + m_repeater_load_->setLoadCap(m_repeater_->getNet("A")->getTotalDownstreamCap()); + m_timing_tree_->performCritPathExtract(m_repeater_->getNet("A")); + delay = m_timing_tree_->calculateCritPathDelay(m_repeater_->getNet("A")) * number_segments; + + // Abort if adding more min sized repeaters does not decrease the delay + if(delay > last_min_size_delay) + { + break; + } + last_min_size_delay = delay; + } + } + Log::printLine(getInstanceName() + " -> Repeater Insertion Ended after Iteration: " + (String)iteration + + ": Required delay = " + (String)required_delay + + ", Delay = " + (String)delay + + ", Slack = " + (String)(required_delay - delay) + + ", Number of repeaters = " + (String)number_segments); + + // Print a warning if the timing is not met + if(required_delay < delay) + { + const String& warning_msg = "[Warning] " + getInstanceName() + " -> Timing not met" + + ": Required delay = " + (String)required_delay + + ", Delay = " + (String)delay + + ", Slack = " + (String)(required_delay - delay) + + ", Number of repeaters = " + (String)number_segments; + Log::printLine(std::cerr, warning_msg); + } + } + + // Update electrical interfaces + getLoad("In_Cap")->setLoadCap(m_repeater_->getNet("A")->getTotalDownstreamCap()); + getDelay("In_to_Out_delay")->setDelay(delay); + getDriver("Out_Ron")->setOutputRes(m_repeater_->getDriver("Y_Ron")->getOutputRes() + (total_wire_res / number_segments)); + + getGenProperties()->set("NumberSegments", number_segments); + + // Update area, power results + resetElectricalAtomicResults(); + addElecticalAtomicResultValues(m_repeater_, number_segments * number_bits); + double wire_area = wire_length * (wire_width + wire_spacing) * number_bits; + addElecticalWireAtomicResultValue(wire_layer, wire_area); + + return; + } + + void RepeatedLink::useModel() + { + // Update the transition information for the modeled repeater + // Since we only modeled one repeater. So the transition information for 0->0 and 1->1 + // is averaged out + const TransitionInfo& trans_In = getInputPort("In")->getTransitionInfo(); + double average_static_transition = (trans_In.getNumberTransitions00() + trans_In.getNumberTransitions11()) / 2.0; + TransitionInfo mod_trans_In(average_static_transition, trans_In.getNumberTransitions01(), average_static_transition); + m_repeater_->getInputPort("A")->setTransitionInfo(mod_trans_In); + m_repeater_->use(); + + // Get parameters + unsigned int number_bits = getParameter("NumberBits").toUInt(); + unsigned int number_segments = getGenProperties()->get("NumberSegments").toUInt(); + + // Propagate the transition information + propagateTransitionInfo(); + + // Update leakage power + double power = 0.0; + power += m_repeater_->getNddPowerResult("Leakage")->calculateSum() * number_segments * number_bits; + getNddPowerResult("Leakage")->setValue(power); + + // Update event result + double energy = 0.0; + energy += m_repeater_->getEventResult("INV")->calculateSum() * number_segments * number_bits; + getEventResult("Send")->setValue(energy); + + return; + } + + void RepeatedLink::propagateTransitionInfo() + { + unsigned int number_segments = getGenProperties()->get("NumberSegments"); + + if((number_segments % 2) == 0) + { + propagatePortTransitionInfo("Out", "In"); + } + else + { + const TransitionInfo& trans_In = getInputPort("In")->getTransitionInfo(); + TransitionInfo trans_Out(trans_In.getNumberTransitions11(), trans_In.getNumberTransitions01(), trans_In.getNumberTransitions00()); + getOutputPort("Out")->setTransitionInfo(trans_Out); + } + return; + } + +} // namespace DSENT + diff --git a/ext/dsent/model/electrical/RepeatedLink.h b/ext/dsent/model/electrical/RepeatedLink.h new file mode 100644 index 000000000..1cd8e3412 --- /dev/null +++ b/ext/dsent/model/electrical/RepeatedLink.h @@ -0,0 +1,44 @@ +#ifndef __DSENT_MODEL_ELECTRICAL_REPEATED_LINK_H__ +#define __DSENT_MODEL_ELECTRICAL_REPEATED_LINK_H__ + +#include "util/CommonType.h" +#include "model/ElectricalModel.h" + +namespace DSENT +{ + class StdCell; + class ElectricalLoad; + class ElectricalTimingTree; + + class RepeatedLink : public ElectricalModel + { + public: + RepeatedLink(const String& instance_name_, const TechModel* tech_model_); + virtual ~RepeatedLink(); + + public: + // Set a list of properties' name needed to construct model + void initParameters(); + // Set a list of properties' name needed to construct model + void initProperties(); + + // Clone and return a new instance + virtual RepeatedLink* clone() const; + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void useModel(); + virtual void propagateTransitionInfo(); + + private: + // Use a repeater and a load to mimic a segment of the repeated link + StdCell* m_repeater_; + ElectricalLoad* m_repeater_load_; + ElectricalTimingTree* m_timing_tree_; + }; // class RepeatedLink +} // namespace DSENT + +#endif // __DSENT_MODEL_ELECTRICAL_REPEATED_LINK_H__ + diff --git a/ext/dsent/model/electrical/RippleAdder.cc b/ext/dsent/model/electrical/RippleAdder.cc new file mode 100644 index 000000000..779cd4798 --- /dev/null +++ b/ext/dsent/model/electrical/RippleAdder.cc @@ -0,0 +1,106 @@ +#include "model/electrical/RippleAdder.h" + +#include <cmath> + +#include "model/PortInfo.h" +#include "model/TransitionInfo.h" +#include "model/EventInfo.h" +#include "model/std_cells/StdCell.h" +#include "model/std_cells/StdCellLib.h" + +namespace DSENT +{ + RippleAdder::RippleAdder(const String& instance_name_, const TechModel* tech_model_) + : ElectricalModel(instance_name_, tech_model_) + { + initParameters(); + initProperties(); + } + + RippleAdder::~RippleAdder() + {} + + void RippleAdder::initParameters() + { + addParameterName("NumberBits"); + return; + } + + void RippleAdder::initProperties() + { + return; + } + + void RippleAdder::constructModel() + { + // Get properties + unsigned int number_bits = (unsigned int) getParameter("NumberBits"); + + //Construct electrical ports and nets + createInputPort("CI"); + createOutputPort("CO"); + for(unsigned int i = 0; i < number_bits; ++i) + { + createInputPort("A" + String(i)); + createInputPort("B" + String(i)); + createOutputPort("S" + String(i)); + createNet("C" + String(i)); + } + createNet("C" + String(number_bits)); + + //Create energy, power, and area results + createElectricalResults(); + getEventInfo("Idle")->setStaticTransitionInfos(); + createElectricalEventResult("Add"); + Result* add_event = getEventResult("Add"); + + // Connect all nets + assign("C0", "CI"); + assign("CO", "C" + String(number_bits)); + for (unsigned int i = 0; i < number_bits; ++i) + { + String n = (String) i; + StdCell* adder = getTechModel()->getStdCellLib()->createStdCell("ADDF", "ADDF_" + n); + adder->construct(); + + //Build electrical connectivity + portConnect(adder, "A", "A" + String(i)); + portConnect(adder, "B", "B" + String(i)); + portConnect(adder, "CI", "C" + String(i)); + portConnect(adder, "S", "S" + String(i)); + portConnect(adder, "CO", "C" + String(i + 1)); + + //Add ADDF instance, leakage power, energy, and add event results + addSubInstances(adder, 1.0); + addElectricalSubResults(adder, 1.0); + add_event->addSubResult(adder->getEventResult("ADDF"), "ADDF_" + n, 1.0); + } + + return; + } + + void RippleAdder::propagateTransitionInfo() + { + unsigned int number_bits = getParameter("NumberBits").toUInt(); + + TransitionInfo current_trans_CI = getInputPort("CI")->getTransitionInfo(); + for(unsigned int i = 0; i < number_bits; ++i) + { + ElectricalModel* adder = (ElectricalModel*)getSubInstance("ADDF_" + String(i)); + + // Propagate input transition info + propagatePortTransitionInfo(adder, "A", "A" + String(i)); + propagatePortTransitionInfo(adder, "B", "B" + String(i)); + assignPortTransitionInfo(adder, "CI", current_trans_CI); + adder->use(); + + // Assign output transition info + propagatePortTransitionInfo("S" + String(i), adder, "S"); + current_trans_CI = adder->getOutputPort("CO")->getTransitionInfo(); + } + getOutputPort("CO")->setTransitionInfo(current_trans_CI); + return; + } + +} // namespace DSENT + diff --git a/ext/dsent/model/electrical/RippleAdder.h b/ext/dsent/model/electrical/RippleAdder.h new file mode 100644 index 000000000..6f5f71072 --- /dev/null +++ b/ext/dsent/model/electrical/RippleAdder.h @@ -0,0 +1,30 @@ +#ifndef __DSENT_MODEL_ELECTRICAL_RIPPLE_ADDER_H__ +#define __DSENT_MODEL_ELECTRICAL_RIPPLE_ADDER_H__ + +#include "util/CommonType.h" +#include "model/ElectricalModel.h" + +namespace DSENT +{ + class RippleAdder : public ElectricalModel + { + public: + RippleAdder(const String& instance_name_, const TechModel* tech_model_); + virtual ~RippleAdder(); + + public: + // Set a list of properties' name needed to construct model + void initParameters(); + // Set a list of properties' name needed to construct model + void initProperties(); + + protected: + // Build the model + virtual void constructModel(); + virtual void propagateTransitionInfo(); + + }; // class RippleAdder +} // namespace DSENT + +#endif // __DSENT_MODEL_ELECTRICAL_TESTMODEL_H__ + diff --git a/ext/dsent/model/electrical/SeparableAllocator.cc b/ext/dsent/model/electrical/SeparableAllocator.cc new file mode 100644 index 000000000..e0965cbe9 --- /dev/null +++ b/ext/dsent/model/electrical/SeparableAllocator.cc @@ -0,0 +1,270 @@ +#include "model/electrical/SeparableAllocator.h" + +#include "model/ModelGen.h" +#include "model/timing_graph/ElectricalNet.h" + +namespace DSENT +{ + SeparableAllocator::SeparableAllocator(const String& instance_name_, const TechModel* tech_model_) + : ElectricalModel(instance_name_, tech_model_) + { + initParameters(); + initProperties(); + } + + SeparableAllocator::~SeparableAllocator() + {} + + void SeparableAllocator::initParameters() + { + addParameterName("NumberRequesters"); + addParameterName("NumberResources"); + addParameterName("IsRequesterFirst", true); + addParameterName("Stage1->ArbiterModel"); + addParameterName("Stage2->ArbiterModel"); + return; + } + + void SeparableAllocator::initProperties() + { + addPropertyName("P(Request)"); + addPropertyName("Act(Request)"); + addPropertyName("P(CK)"); + addPropertyName("Act(CK)"); + return; + } + + SeparableAllocator* SeparableAllocator::clone() const + { + // TODO + return NULL; + } + + void SeparableAllocator::constructModel() + { + // Get parameters + unsigned int number_requesters = getParameter("NumberRequesters").toUInt(); + unsigned int number_resources = getParameter("NumberResources").toUInt(); + bool is_requester_first = getParameter("IsRequesterFirst").toBool(); + const String& stage1_arbiter_model = getParameter("Stage1->ArbiterModel"); + const String& stage2_arbiter_model = getParameter("Stage2->ArbiterModel"); + + ASSERT(number_requesters > 0, "[Error] " + getInstanceName() + + " -> Number of requesters must be > 0!"); + ASSERT(number_resources > 0, "[Error] " + getInstanceName() + + " -> Number of resources must be > 0!"); + + // Create area, power, and event results + createElectricalResults(); + addEventResult(new Result("Allocate")); + + // Create ports + createInputPort("CK"); + for(unsigned int i = 0; i < number_requesters; ++i) + { + createInputPort("Request" + (String)i, makeNetIndex(0, number_resources-1)); + createOutputPort("Grant" + (String)i, makeNetIndex(0, number_resources-1)); + } + + // If is_requester_first is set, requests from the same requester will be arbitrate + // on stage 1 + if(is_requester_first) + { + // Init stage 1 arbiters + for(unsigned int i = 0; i < number_requesters; ++i) + { + ElectricalModel* arb = (ElectricalModel*)ModelGen::createModel(stage1_arbiter_model, "Stage1Arb" + (String)i, getTechModel()); + arb->setParameter("NumberRequests", number_resources); + arb->construct(); + + addSubInstances(arb, 1.0); + addElectricalSubResults(arb, 1.0); + + getEventResult("Allocate")->addSubResult(arb->getEventResult("Arbitrate"), arb->getInstanceName(), 1.0); + + createNet("Stage1Arb_In" + (String)i, makeNetIndex(0, number_resources-1)); + createNet("Stage1Arb_Out" + (String)i, makeNetIndex(0, number_resources-1)); + + portConnect(arb, "CK", "CK"); + assign("Stage1Arb_In" + (String)i, "Request" + (String)i); + for(unsigned int j = 0; j < number_resources; ++j) + { + portConnect(arb, "Request" + (String)j, "Stage1Arb_In" + (String)i, makeNetIndex(j)); + portConnect(arb, "Grant" + (String)j, "Stage1Arb_Out" + (String)i, makeNetIndex(j)); + } + } + + // Init stage 2 arbiters + for(unsigned int i = 0; i < number_resources; ++i) + { + ElectricalModel* arb = (ElectricalModel*)ModelGen::createModel(stage2_arbiter_model, "Stage2Arb" + (String)i, getTechModel()); + arb->setParameter("NumberRequests", number_requesters); + arb->construct(); + + addSubInstances(arb, 1.0); + addElectricalSubResults(arb, 1.0); + + getEventResult("Allocate")->addSubResult(arb->getEventResult("Arbitrate"), arb->getInstanceName(), 1.0); + + createNet("Stage2Arb_In" + (String)i, makeNetIndex(0, number_requesters-1)); + createNet("Stage2Arb_Out" + (String)i, makeNetIndex(0, number_requesters-1)); + + portConnect(arb, "CK", "CK"); + for(unsigned int j = 0; j < number_requesters; ++j) + { + assign("Stage2Arb_In" + (String)i, makeNetIndex(j), "Stage1Arb_Out" + (String)j, makeNetIndex(i)); + portConnect(arb, "Request" + (String)j, "Stage2Arb_In" + (String)i, makeNetIndex(j)); + portConnect(arb, "Grant" + (String)j, "Stage2Arb_Out" + (String)i, makeNetIndex(j)); + assign("Grant" + (String)j, makeNetIndex(i), "Stage2Arb_Out" + (String)i, makeNetIndex(j)); + } + } + } + else + { + // Init stage 1 arbiters + for(unsigned int i = 0; i < number_resources; ++i) + { + ElectricalModel* arb = (ElectricalModel*)ModelGen::createModel(stage1_arbiter_model, "Stage1Arb" + (String)i, getTechModel()); + arb->setParameter("NumberRequests", number_requesters); + arb->construct(); + + addSubInstances(arb, 1.0); + addElectricalSubResults(arb, 1.0); + + getEventResult("Allocate")->addSubResult(arb->getEventResult("Arbitrate"), arb->getInstanceName(), 1.0); + + createNet("Stage1Arb_In" + (String)i, makeNetIndex(0, number_requesters-1)); + createNet("Stage1Arb_Out" + (String)i, makeNetIndex(0, number_requesters-1)); + + portConnect(arb, "CK", "CK"); + for(unsigned int j = 0; j < number_requesters; ++j) + { + assign("Stage1Arb_In" + (String)i, makeNetIndex(j), "Request" + (String)j, makeNetIndex(i)); + portConnect(arb, "Request" + (String)j, "Stage1Arb_In" + (String)i, makeNetIndex(j)); + portConnect(arb, "Grant" + (String)j, "Stage1Arb_Out" + (String)i, makeNetIndex(j)); + } + } + + // Init stage 2 arbiters + for(unsigned int i = 0; i < number_requesters; ++i) + { + ElectricalModel* arb = (ElectricalModel*)ModelGen::createModel(stage2_arbiter_model, "Stage2Arb" + (String)i, getTechModel()); + arb->setParameter("NumberRequests", number_requesters); + arb->construct(); + + addSubInstances(arb, 1.0); + addElectricalSubResults(arb, 1.0); + + getEventResult("Allocate")->addSubResult(arb->getEventResult("Arbitrate"), arb->getInstanceName(), 1.0); + + createNet("Stage2Arb_In" + (String)i, makeNetIndex(0, number_resources-1)); + createNet("Stage2Arb_Out" + (String)i, makeNetIndex(0, number_resources-1)); + + portConnect(arb, "CK", "CK"); + for(unsigned int j = 0; j < number_resources; ++j) + { + assign("Stage2Arb_In" + (String)i, makeNetIndex(j), "Stage1Arb_Out" + (String)j, makeNetIndex(i)); + portConnect(arb, "Request" + (String)j, "Stage2Arb_In", makeNetIndex(j)); + portConnect(arb, "Grant" + (String)j, "Stage2Arb_Out", makeNetIndex(j)); + } + assign("Grant" + (String)i, "Stage2Arb_Out" + (String)i); + } + } + return; + } + + void SeparableAllocator::updateModel() + { + // Get parameters + unsigned int number_requesters = getParameter("NumberRequesters").toUInt(); + unsigned int number_resources = getParameter("NumberResources").toUInt(); + bool is_requester_first = getParameter("IsRequesterFirst").toBool(); + + // Get probabilities from inputs + const String& P_request = getProperty("P(Request)"); + const String& act_request = getProperty("Act(Request)"); + const String& P_CK = getProperty("P(CK)"); + const String& act_CK = getProperty("Act(CK)"); + + const vector<double>& P_request_vector = LibUtil::castStringVector<double>(P_request.split("[,]")); + const vector<double>& act_request_vector = LibUtil::castStringVector<double>(act_request.split("[,]")); + + ASSERT(P_request_vector.size() == (number_requesters * number_resources), "[Error] " + getInstanceName() + + " -> Expecting " + (String)(number_requesters * number_resources) + + " request probabilities, but got " + P_request); + ASSERT(act_request_vector.size() == (number_requesters * number_resources), "[Error] " + getInstanceName() + + " -> Expecting " + (String)(number_requesters * number_resources) + + " request actvities multiplier, but got " + act_request); + + vector<double> P_int_request_vector(number_requesters * number_resources, 0.0); + vector<double> act_int_request_vector(number_requesters * number_resources, 0.0); + vector<double> P_out_request_vector(number_requesters * number_resources, 0.0); + vector<double> act_out_request_vector(number_requesters * number_resources, 0.0); + if(is_requester_first) + { + // Update stage1 arbiter + for(unsigned int i = 0; i < number_requesters; ++i) + { + vector<double> P_arb_request_vector(number_resources, 0.0); + vector<double> act_arb_request_vector(number_resources, 0.0); + for(unsigned int j = 0; j < number_resources; ++j) + { + P_arb_request_vector[j] = P_request_vector[i * number_resources + j]; + act_arb_request_vector[j] = act_request_vector[i * number_resources + j]; + } + + Model* arb = getSubInstance("Stage1Arb" + (String)i); + arb->setProperty("P(Request)", LibUtil::vectorToString(P_arb_request_vector)); + arb->setProperty("Act(Request)", LibUtil::vectorToString(act_arb_request_vector)); + arb->setProperty("P(CK)", P_CK); + arb->setProperty("Act(CK)", act_CK); + arb->update(); + + const vector<double>& P_arb_out_request_vector = LibUtil::castStringVector<double>(arb->getGenProperties()->get("P(Grant)").split("[,]")); + const vector<double>& act_arb_out_request_vector = LibUtil::castStringVector<double>(arb->getGenProperties()->get("Act(Grant)").split("[,]")); + for(unsigned int j = 0; j < number_resources; ++j) + { + P_int_request_vector[i * number_resources + j] = P_arb_out_request_vector[j]; + act_int_request_vector[i * number_resources + j] = act_arb_out_request_vector[j]; + } + } + // Update stage2 arbiter + for(unsigned int i = 0; i < number_resources; ++i) + { + vector<double> P_arb_request_vector(number_requesters, 0.0); + vector<double> act_arb_request_vector(number_requesters, 0.0); + for(unsigned int j = 0; j < number_requesters; ++j) + { + P_arb_request_vector[j] = P_int_request_vector[j * number_resources + i]; + act_arb_request_vector[j] = act_int_request_vector[j * number_resources + i]; + } + + Model* arb = getSubInstance("Stage2Arb" + (String)i); + arb->setProperty("P(Request)", LibUtil::vectorToString(P_arb_request_vector)); + arb->setProperty("Act(Request)", LibUtil::vectorToString(act_arb_request_vector)); + arb->setProperty("P(CK)", P_CK); + arb->setProperty("Act(CK)", act_CK); + arb->update(); + + const vector<double>& P_arb_out_request_vector = LibUtil::castStringVector<double>(arb->getGenProperties()->get("P(Grant)").split("[,]")); + const vector<double>& act_arb_out_request_vector = LibUtil::castStringVector<double>(arb->getGenProperties()->get("Act(Grant)").split("[,]")); + for(unsigned int j = 0; j < number_requesters; ++j) + { + P_out_request_vector[j * number_resources + i] = P_arb_out_request_vector[j]; + act_out_request_vector[j * number_resources + i] = act_arb_out_request_vector[j]; + } + } + } + else + { + + } + + // Update output probabilities + getGenProperties()->set("P(Grant)", LibUtil::vectorToString(P_out_request_vector)); + getGenProperties()->set("Act(Grant)", LibUtil::vectorToString(act_out_request_vector)); + + return; + } +} // namespace DSENT + diff --git a/ext/dsent/model/electrical/SeparableAllocator.h b/ext/dsent/model/electrical/SeparableAllocator.h new file mode 100644 index 000000000..21519bf38 --- /dev/null +++ b/ext/dsent/model/electrical/SeparableAllocator.h @@ -0,0 +1,33 @@ +#ifndef __DSENT_MODEL_ELECTRICAL_SEPARABLE_ALLOCATOR_H__ +#define __DSENT_MODEL_ELECTRICAL_SEPARABLE_ALLOCATOR_H__ + +#include "util/CommonType.h" +#include "model/ElectricalModel.h" + +namespace DSENT +{ + class SeparableAllocator : public ElectricalModel + { + public: + SeparableAllocator(const String& instance_name_, const TechModel* tech_model_); + virtual ~SeparableAllocator(); + + public: + // Set a list of properties' name needed to construct model + void initParameters(); + // Set a list of properties' name needed to construct model + void initProperties(); + + // Clone and return a new instance + virtual SeparableAllocator* clone() const; + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + + }; // class SeparableAllocator +} // namespace DSENT + +#endif // __DSENT_MODEL_ELECTRICAL_SEPARABLE_ALLOCATOR_H__ + diff --git a/ext/dsent/model/electrical/TestModel.cc b/ext/dsent/model/electrical/TestModel.cc new file mode 100644 index 000000000..24f1fab43 --- /dev/null +++ b/ext/dsent/model/electrical/TestModel.cc @@ -0,0 +1,218 @@ +#include "model/electrical/TestModel.h" + +#include <cmath> + +#include "model/std_cells/StdCell.h" +#include "model/std_cells/StdCellLib.h" +#include "model/electrical/RippleAdder.h" +#include "model/electrical/Multiplexer.h" +#include "model/timing_graph/ElectricalNet.h" +#include "model/timing_graph/ElectricalDriver.h" +#include "model/timing_graph/ElectricalLoad.h" +#include "model/timing_graph/ElectricalTimingTree.h" + +namespace DSENT +{ + TestModel::TestModel(const String& instance_name_, const TechModel* tech_model_) + : ElectricalModel(instance_name_, tech_model_) + { + initProperties(); + } + + TestModel::~TestModel() + {} + + void TestModel::initProperties() + { + return; + } + + TestModel* TestModel::clone() const + { + return NULL; + } + + void TestModel::constructModel() + { + unsigned int num_bits = 64; + unsigned int mux_bits = 1; + + // Create the instance + createNet("CK"); + createNet("CI"); + getNet("CI")->setDistributedCap(100e-15); + getNet("CI")->setDistributedRes(10); + createNet("CO"); + createNet("A", makeNetIndex(0, num_bits - 1)); + createNet("B", makeNetIndex(0, num_bits - 1)); + createNet("S", makeNetIndex(0, num_bits - 1)); + + StdCell* ci_reg = getTechModel()->getStdCellLib()->createStdCell("DFFQ", "DFFQ-CI"); + ci_reg->setProperty("P(D)", 0.5); + ci_reg->setProperty("P(CK)", 0.5); + ci_reg->construct(); + portConnect(ci_reg, "Q", "CI"); + portConnect(ci_reg, "CK", "CK"); + //ci_reg->connect("Q", getNet("CI")); + //ci_reg->connect("CK", getNet("CK")); + addSubInstances(ci_reg, 1.0); + + StdCell* co_reg = getTechModel()->getStdCellLib()->createStdCell("DFFQ", "DFFQ-CO"); + co_reg->setProperty("P(D)", 0.5); + co_reg->setProperty("P(CK)", 0.5); + co_reg->construct(); + portConnect(co_reg, "D", "CO"); + portConnect(co_reg, "CK", "CK"); + //co_reg->connect("D", getNet("CO")); + //co_reg->connect("CK", getNet("CK")); + addSubInstances(co_reg, 1.0); + + for (unsigned int i = 0; i < num_bits; i++) + { + StdCell* a_reg = getTechModel()->getStdCellLib()->createStdCell("DFFQ", "DFFQ-A[" + (String) i + "]"); + a_reg->setProperty("P(D)", 0.5); + a_reg->setProperty("P(CK)", 0.5); + a_reg->construct(); + portConnect(a_reg, "Q", "A", makeNetIndex(i)); + portConnect(a_reg, "CK", "CK"); + //a_reg->connect("Q", getNet("A[" + (String) i + "]")); + //a_reg->connect("CK", getNet("CK")); + addSubInstances(a_reg, 1.0); + + StdCell* b_reg = getTechModel()->getStdCellLib()->createStdCell("DFFQ", "DFFQ-B[" + (String) i + "]"); + b_reg->setProperty("P(D)", 0.5); + b_reg->setProperty("P(CK)", 0.5); + b_reg->construct(); + portConnect(b_reg, "Q", "B", makeNetIndex(i)); + portConnect(b_reg, "CK", "CK"); + //b_reg->connect("Q", getNet("B[" + (String) i + "]")); + //b_reg->connect("CK", getNet("CK")); + addSubInstances(b_reg, 1.0); + + StdCell* s_reg = getTechModel()->getStdCellLib()->createStdCell("DFFQ", "DFFQ-S[" + (String) i + "]"); + s_reg->setProperty("P(D)", 0.5); + s_reg->setProperty("P(CK)", 0.5); + s_reg->construct(); + portConnect(s_reg, "D", "S", makeNetIndex(i)); + portConnect(s_reg, "CK", "CK"); + //s_reg->connect("D", getNet("A[" + (String) i + "]")); + //s_reg->connect("CK", getNet("CK")); + addSubInstances(s_reg, 1.0); + } + + + //Create some adders! + + ElectricalModel* ripple_adder = new RippleAdder("Adder_1", getTechModel()); + ripple_adder->setParameter("NumberBits", num_bits); + ripple_adder->setProperty("P(A)", 0.5); + ripple_adder->setProperty("P(B)", 0.5); + ripple_adder->setProperty("P(CI)", 0.5); + + ripple_adder->construct(); + addSubInstances(ripple_adder, 1.0); + portConnect(ripple_adder, "CI", "CI"); + portConnect(ripple_adder, "CO", "CO"); + portConnect(ripple_adder, "A", "A"); + portConnect(ripple_adder, "B", "B"); + portConnect(ripple_adder, "S", "S"); + + ElectricalModel* multiplexer = new Multiplexer("Mux_1", getTechModel()); + multiplexer->setParameter("NumberInputs", 2); + multiplexer->setParameter("NumberBits", mux_bits); + multiplexer->setParameter("BitDuplicate", "FALSE"); + //multiplexer->setProperty("P(In)", "[0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5]"); + //multiplexer->setProperty("P(Sel)", "[0.5, 0.5, 0.5]"); + //multiplexer->setProperty("Act(In)", "[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]"); + //multiplexer->setProperty("Act(Sel)", "[2.0, 4.0, 8.0]"); + multiplexer->setProperty("P(In)", "[0.5, 0.5]"); + multiplexer->setProperty("P(Sel)", "[0.5]"); + multiplexer->setProperty("Act(In)", "[1.0, 1.0]"); + multiplexer->setProperty("Act(Sel)", "[1.0]"); + multiplexer->construct(); + + createNet("In0", makeNetIndex(0, mux_bits-1)); + createNet("In1", makeNetIndex(0, mux_bits-1)); + createNet("In2", makeNetIndex(0, mux_bits-1)); + createNet("In3", makeNetIndex(0, mux_bits-1)); + createNet("In4", makeNetIndex(0, mux_bits-1)); + createNet("Out", makeNetIndex(0, mux_bits-1)); + + portConnect(multiplexer, "In0", "In0"); + portConnect(multiplexer, "In1", "In1"); + //portConnect(multiplexer, "In2", "In2"); + //portConnect(multiplexer, "In3", "In3"); + //portConnect(multiplexer, "In4", "In4"); + portConnect(multiplexer, "Out", "Out"); + + for (unsigned int i = 0; i < mux_bits; ++i) + { + String n = (String) i; + + createLoad("OutLoad[" + n + "]"); + getLoad("OutLoad[" + n + "]")->setLoadCap(100e-15); + + getNet("Out", makeNetIndex(i))->addDownstreamNode(getLoad("OutLoad[" + n + "]")); + } + createNet("Sel", makeNetIndex(0, 2)); + assign("Sel", makeNetIndex(0), "CK"); + assign("Sel", makeNetIndex(1), "CK"); + assign("Sel", makeNetIndex(2), "CK"); + + //portConnect(multiplexer, "Sel", "Sel"); + + addSubInstances(multiplexer, 1.0); + + //ElectricalTimingAbstract* abstract = new ElectricalTimingAbstract("HAHAHA", getTechModel(), ripple_adder); + //abstract->buildAbstract(); + + return; + } + + void TestModel::updateModel() + { + Model::updateModel(); + + //ElectricalTimingTree* t = new ElectricalTimingTree("Add", this); + //t->performTimingOpt(getNet("CK"), 4.21300e-8); + //t->performTimingOpt(getNet("CK"), 1e-9); + //delete t; + + ElectricalTimingTree* t2 = new ElectricalTimingTree("Mux", this); + t2->performTimingOpt(getNet("In1", makeNetIndex(0)), 500e-12); + delete t2; + + + } + + void TestModel::evaluateModel() + { + Model::evaluateModel(); + + //ripple_adder->getNddPowerResult("LeakagePower")->print("RippleAdder->Leakage", 10, cout); + getSubInstance("Adder_1")->getNddPowerResult("Leakage")->print("RippleAdder->Leakage", 0, cout); + //ripple_adder->getAreaResult("TotalArea")->print("RippleAdder->TotalArea", 10, cout); + getSubInstance("Adder_1")->getAreaResult("Active")->print("RippleAdder->ActiveArea", 0, cout); + //ripple_adder->getEventResult("AddEvent")->print("RippleAdder->AddEvent", 10, cout); + getSubInstance("Adder_1")->getEventResult("Add")->print("RippleAdder->Add", 0, cout); + + getSubInstance("Mux_1")->getNddPowerResult("Leakage")->print("Multiplexer->Leakage", 0, cout); + getSubInstance("Mux_1")->getAreaResult("Active")->print("Multiplexer->ActiveArea", 0, cout); + getSubInstance("Mux_1")->getEventResult("Mux")->print("Multiplexer->MuxEvent", 0, cout); + cout << "Multiplexer->P(Out) = " << getSubInstance("Mux_1")->getGenProperties()->get("P(Out)") << endl; + + getSubInstance("DFFQ-CI")->getNddPowerResult("Leakage")->print("DFFQ-CI->Leakage", 0, cout); + getSubInstance("DFFQ-CI")->getAreaResult("Active")->print("DFFQ-CI->ActiveArea", 0, cout); + getSubInstance("DFFQ-CI")->getEventResult("DFF")->print("DFFQ-CI->DFF", 0, cout); + getSubInstance("DFFQ-CI")->getEventResult("CK")->print("DFFQ-CI->CK", 0, cout); + + //ripple_adder->getNddPowerResult("LeakagePower")->print("RippleAdder->Leakage", 10, cout); + getSubInstance("Adder_1")->getNddPowerResult("Leakage")->print("RippleAdder->Leakage", 0, cout); + //ripple_adder->getAreaResult("TotalArea")->print("RippleAdder->TotalArea", 10, cout); + getSubInstance("Adder_1")->getAreaResult("Active")->print("RippleAdder->ActiveArea", 0, cout); + //ripple_adder->getEventResult("AddEvent")->print("RippleAdder->AddEvent", 10, cout); + getSubInstance("Adder_1")->getEventResult("Add")->print("RippleAdder->AddEvent", 0, cout); + } + +} // namespace DSENT + diff --git a/ext/dsent/model/electrical/TestModel.h b/ext/dsent/model/electrical/TestModel.h new file mode 100644 index 000000000..5e07ea30c --- /dev/null +++ b/ext/dsent/model/electrical/TestModel.h @@ -0,0 +1,32 @@ +#ifndef __DSENT_MODEL_ELECTRICAL_TESTMODEL_H__ +#define __DSENT_MODEL_ELECTRICAL_TESTMODEL_H__ + +#include "util/CommonType.h" +#include "model/ElectricalModel.h" + +namespace DSENT +{ + class TestModel : public ElectricalModel + { + public: + TestModel(const String& instance_name_, const TechModel* tech_model_); + virtual ~TestModel(); + + public: + // Set a list of properties' name needed to construct model + void initProperties(); + + // Clone and return a new instance + virtual TestModel* clone() const; + + protected: + // Build the model + void constructModel(); + void updateModel(); + void evaluateModel(); + + }; // class TestModel +} // namespace DSENT + +#endif // __DSENT_MODEL_ELECTRICAL_TESTMODEL_H__ + diff --git a/ext/dsent/model/electrical/router/Router.cc b/ext/dsent/model/electrical/router/Router.cc new file mode 100644 index 000000000..c079bd1d5 --- /dev/null +++ b/ext/dsent/model/electrical/router/Router.cc @@ -0,0 +1,536 @@ +#include "model/electrical/router/Router.h" + +#include <cmath> +#include <vector> + +#include "model/PortInfo.h" +#include "model/EventInfo.h" +#include "model/TransitionInfo.h" +#include "model/ModelGen.h" +#include "model/std_cells/StdCellLib.h" +#include "model/std_cells/StdCell.h" +#include "model/electrical/router/RouterInputPort.h" +#include "model/electrical/router/RouterSwitchAllocator.h" +#include "model/timing_graph/ElectricalNet.h" + +namespace DSENT +{ + using std::sqrt; + using std::vector; + + using LibUtil::castStringVector; + using LibUtil::vectorToString; + + Router::Router(const String& instance_name_, const TechModel* tech_model_) + : ElectricalModel(instance_name_, tech_model_) + { + initParameters(); + initProperties(); + } + + Router::~Router() + {} + + void Router::initParameters() + { + addParameterName("NumberInputPorts"); + addParameterName("NumberOutputPorts"); + addParameterName("NumberBitsPerFlit"); + addParameterName("NumberVirtualNetworks"); + addParameterName("NumberVirtualChannelsPerVirtualNetwork"); + addParameterName("NumberBuffersPerVirtualChannel"); + // Spec for input port + addParameterName("InputPort->BufferModel"); + // Spec for crossbar + addParameterName("CrossbarModel"); + // Spec for switch allocator + addParameterName("SwitchAllocator->ArbiterModel"); + // Spec for clock tree + addParameterName("ClockTreeModel"); + addParameterName("ClockTree->NumberLevels"); + addParameterName("ClockTree->WireLayer"); + addParameterName("ClockTree->WireWidthMultiplier"); + addParameterName("ClockTree->WireSpacingMultiplier", 3.0); + return; + } + + void Router::initProperties() + { + return; + } + + Router* Router::clone() const + { + // TODO + return NULL; + } + + void Router::constructModel() + { + // Get parameters + unsigned int number_input_ports = getParameter("NumberInputPorts").toUInt(); + unsigned int number_output_ports = getParameter("NumberOutputPorts").toUInt(); + unsigned int number_bits_per_flit = getParameter("NumberBitsPerFlit").toUInt(); + + ASSERT(number_input_ports > 0, "[Error] " + getInstanceName() + + " -> Number of input ports must be > 0!"); + ASSERT(number_output_ports > 0, "[Error] " + getInstanceName() + + " -> Number of output ports must be > 0!"); + ASSERT(number_bits_per_flit > 0, "[Error] " + getInstanceName() + + " -> Number of bits per buffer must be > 0!"); + + // Create ports + createInputPort("CK"); + for(unsigned int i = 0; i < number_input_ports; ++i) + { + createInputPort("FlitIn" + (String)i, makeNetIndex(0, number_bits_per_flit-1)); + } + for(unsigned int i = 0; i < number_output_ports; ++i) + { + createOutputPort("FlitOut" + (String)i, makeNetIndex(0, number_bits_per_flit-1)); + } + + // Create area, power, event results + createElectricalResults(); + getEventInfo("Idle")->setStaticTransitionInfos(); + getEventInfo("Idle")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0)); + + createElectricalEventResult("ReadBuffer"); + getEventInfo("ReadBuffer")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0)); + createElectricalEventResult("WriteBuffer"); + getEventInfo("WriteBuffer")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0)); + for(unsigned int i = 1; i <= number_output_ports; ++i) + { + createElectricalEventResult("TraverseCrossbar->Multicast" + (String)i); + getEventInfo("TraverseCrossbar->Multicast" + (String)i)->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0)); + } + createElectricalEventResult("ArbitrateSwitch->ArbitrateStage1"); + createElectricalEventResult("ArbitrateSwitch->ArbitrateStage2"); + createElectricalEventResult("DistributeClock"); + getEventInfo("DistributeClock")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0)); + + // Create intermediate nets + createNet("PipelineReg0_In"); + createNet("PipelineReg0_Out"); + createNet("PipelineReg1_In"); + createNet("PipelineReg1_Out"); + for(unsigned int i = 0; i < number_output_ports; ++i) + { + createNet("PipelineReg2_In" + (String)i); + createNet("PipelineReg2_Out" + (String)i); + } + + createRouterInputPort(); + createSwitchAllocator(); + createVirtualChannelAllocator(); + createCrossbar(); + createClockTree(); + createPipelineReg(); + + // Get generated numbers + unsigned int number_crossbar_selects = getGenProperties()->get("Crossbar->NumberSelects"); + + // Add write buffer event + getEventResult("WriteBuffer")->addSubResult(getSubInstance("PipelineReg0")->getEventResult("DFFD"), "PipelineReg0", number_bits_per_flit); + getEventResult("WriteBuffer")->addSubResult(getSubInstance("PipelineReg0")->getEventResult("DFFQ"), "PipelineReg0", number_bits_per_flit); + getEventResult("WriteBuffer")->addSubResult(getSubInstance("PipelineReg0")->getEventResult("CK"), "PipelineReg0", number_bits_per_flit); + getEventResult("WriteBuffer")->addSubResult(getSubInstance("InputPort")->getEventResult("WriteBuffer"), "InputPort", 1.0); + + // Add read buffer event + getEventResult("ReadBuffer")->addSubResult(getSubInstance("InputPort")->getEventResult("ReadBuffer"), "InputPort", 1.0); + getEventResult("ReadBuffer")->addSubResult(getSubInstance("PipelineReg1")->getEventResult("DFFD"), "PipelineReg1", number_bits_per_flit); + getEventResult("ReadBuffer")->addSubResult(getSubInstance("PipelineReg1")->getEventResult("DFFQ"), "PipelineReg1", number_bits_per_flit); + getEventResult("ReadBuffer")->addSubResult(getSubInstance("PipelineReg1")->getEventResult("CK"), "PipelineReg1", number_bits_per_flit); + + // Add crossbar traversal event + for(unsigned int i = 1; i <= number_output_ports; ++i) + { + Result* traverse_crossbar_event = getEventResult("TraverseCrossbar->Multicast" + (String)i); + traverse_crossbar_event->addSubResult(getSubInstance("Crossbar_Sel_DFF")->getEventResult("DFFD"), "Crossbar_Sel_DFF", number_crossbar_selects); + traverse_crossbar_event->addSubResult(getSubInstance("Crossbar_Sel_DFF")->getEventResult("DFFQ"), "Crossbar_Sel_DFF", number_crossbar_selects); + traverse_crossbar_event->addSubResult(getSubInstance("Crossbar_Sel_DFF")->getEventResult("CK"), "Crossbar_Sel_DFF", number_crossbar_selects); + traverse_crossbar_event->addSubResult(getSubInstance("Crossbar")->getEventResult("Multicast" + (String)i), "Crossbar", 1.0); + for(unsigned int j = 0; j < i; ++j) + { + traverse_crossbar_event->addSubResult(getSubInstance("PipelineReg2_" + (String)j)->getEventResult("DFFD"), "PipelineReg2_" + (String)j, number_bits_per_flit); + traverse_crossbar_event->addSubResult(getSubInstance("PipelineReg2_" + (String)j)->getEventResult("DFFQ"), "PipelineReg2_" + (String)j, number_bits_per_flit); + traverse_crossbar_event->addSubResult(getSubInstance("PipelineReg2_" + (String)j)->getEventResult("CK"), "PipelineReg2_" + (String)j, number_bits_per_flit); + } + } + + // Add stage1 allocator arbitrate + Result* arb_sw_stage1_event = getEventResult("ArbitrateSwitch->ArbitrateStage1"); + arb_sw_stage1_event->addSubResult(getSubInstance("SwitchAllocator")->getEventResult("ArbitrateStage1"), "SwitchAllocator", 1.0); + + // Add stage2 allocator arbitrate + Result* arb_sw_stage2_event = getEventResult("ArbitrateSwitch->ArbitrateStage2"); + arb_sw_stage2_event->addSubResult(getSubInstance("SwitchAllocator")->getEventResult("ArbitrateStage2"), "SwitchAllocator", 1.0); + + // Add CK event + getEventResult("DistributeClock")->addSubResult(getSubInstance("ClockTree")->getEventResult("Send"), "ClockTree", 1.0); + return; + } + + void Router::updateModel() + { + // Get parameters + unsigned int number_output_ports = getParameter("NumberOutputPorts").toUInt(); + + // Update other components + getSubInstance("PipelineReg0")->update(); + getSubInstance("InputPort")->update(); + getSubInstance("PipelineReg1")->update(); + getSubInstance("Crossbar_Sel_DFF")->update(); + getSubInstance("Crossbar")->update(); + for(unsigned int i = 0; i < number_output_ports; ++i) + { + getSubInstance("PipelineReg2_" + (String)i)->update(); + } + getSubInstance("SwitchAllocator")->update(); + + // Update clock tree + double total_clock_tree_cap = getNet("CK")->getTotalDownstreamCap(); + double router_area = getAreaResult("Active")->calculateSum(); + Model* clock_tree = getSubInstance("ClockTree"); + clock_tree->setProperty("SitePitch", sqrt(router_area)); + clock_tree->setProperty("TotalLoadCapPerBit", total_clock_tree_cap); + clock_tree->update(); + + return; + } + + void Router::propagateTransitionInfo() + { + // Update probability + unsigned int number_output_ports = getParameter("NumberOutputPorts"); + + // Current event + const String& current_event = getGenProperties()->get("UseModelEvent"); + + ElectricalModel* pipeline_reg0 = (ElectricalModel*)getSubInstance("PipelineReg0"); + propagatePortTransitionInfo(pipeline_reg0, "D", "FlitIn0"); + propagatePortTransitionInfo(pipeline_reg0, "CK", "CK"); + pipeline_reg0->use(); + + ElectricalModel* input_port = (ElectricalModel*)getSubInstance("InputPort"); + propagatePortTransitionInfo(input_port, "FlitIn", pipeline_reg0, "Q"); + propagatePortTransitionInfo(input_port, "CK", "CK"); + input_port->getGenProperties()->set("UseModelEvent", "ReadWrite"); + input_port->use(); + + ElectricalModel* pipeline_reg1 = (ElectricalModel*)getSubInstance("PipelineReg1"); + propagatePortTransitionInfo(pipeline_reg1, "D", "FlitIn0"); + propagatePortTransitionInfo(pipeline_reg1, "CK", "CK"); + pipeline_reg1->use(); + + ElectricalModel* crossbar_sel_dff = (ElectricalModel*)getSubInstance("Crossbar_Sel_DFF"); + assignPortTransitionInfo(crossbar_sel_dff, "D", TransitionInfo()); + propagatePortTransitionInfo(crossbar_sel_dff, "CK", "CK"); + crossbar_sel_dff->use(); + + ElectricalModel* crossbar = (ElectricalModel*)getSubInstance("Crossbar"); + bool is_crossbar_event = false; + for(unsigned int i = 1; i <= number_output_ports; ++i) + { + if(current_event == ("TraverseCrossbar->Multicast" + (String)i)) + { + is_crossbar_event = true; + // Assume the flit is sent from port 0 to port 0~i-1 + // Apply default transition info + crossbar->applyTransitionInfo("Multicast" + (String)i); + // Overwrite transition info + propagatePortTransitionInfo(crossbar, "In0", "FlitIn0"); + break; + } + } + if(is_crossbar_event == false) + { + crossbar->applyTransitionInfo("Multicast1"); + propagatePortTransitionInfo(crossbar, "In0", "FlitIn0"); + } + crossbar->use(); + + vector<ElectricalModel*> pipeline_reg2s(number_output_ports, NULL); + for(unsigned int i = 0; i < number_output_ports; ++i) + { + pipeline_reg2s[i] = (ElectricalModel*)getSubInstance("PipelineReg2_" + (String)i); + propagatePortTransitionInfo(pipeline_reg2s[i], "D", "FlitIn0"); + propagatePortTransitionInfo(pipeline_reg2s[i], "CK", "CK"); + pipeline_reg2s[i]->use(); + } + + ElectricalModel* sw_allocator = (ElectricalModel*)getSubInstance("SwitchAllocator"); + if(current_event == "ArbitrateSwitch->ArbitrateStage1") + { + sw_allocator->applyTransitionInfo("ArbitrateStage1"); + } + else if(current_event == "ArbitrateSwitch->ArbitrateStage2") + { + sw_allocator->applyTransitionInfo("ArbitrateStage2"); + } + else + { + sw_allocator->applyTransitionInfo("Idle"); + } + sw_allocator->use(); + + ElectricalModel* clock_tree = (ElectricalModel*)getSubInstance("ClockTree"); + propagatePortTransitionInfo(clock_tree, "In", "CK"); + clock_tree->use(); + return; + } + + void Router::createRouterInputPort() + { + // Get parameters + unsigned int number_input_ports = getParameter("NumberInputPorts").toUInt(); + unsigned int number_vns = getParameter("NumberVirtualNetworks").toUInt(); + const String& number_vcs_per_vn = getParameter("NumberVirtualChannelsPerVirtualNetwork"); + const String& number_bufs_per_vc = getParameter("NumberBuffersPerVirtualChannel"); + unsigned int number_bits_per_flit = getParameter("NumberBitsPerFlit").toUInt(); + const String& buffer_model = getParameter("InputPort->BufferModel"); + + // Init input port model + const String& input_port_name = "InputPort"; + RouterInputPort* input_port = new RouterInputPort(input_port_name, getTechModel()); + input_port->setParameter("NumberVirtualNetworks", number_vns); + input_port->setParameter("NumberVirtualChannelsPerVirtualNetwork", number_vcs_per_vn); + input_port->setParameter("NumberBuffersPerVirtualChannel", number_bufs_per_vc); + input_port->setParameter("NumberBitsPerFlit", number_bits_per_flit); + input_port->setParameter("BufferModel", buffer_model); + input_port->construct(); + + unsigned int number_input_port_outputs = input_port->getGenProperties()->get("NumberOutputs"); + unsigned int number_input_port_addr_bits = input_port->getGenProperties()->get("NumberAddressBits"); + getGenProperties()->set("InputPort->NumberOutputs", number_input_port_outputs); + getGenProperties()->set("InputPort->NumberAddressBits", number_input_port_addr_bits); + + unsigned int total_number_vcs = input_port->getGenProperties()->get("TotalNumberVirtualChannels"); + getGenProperties()->set("TotalNumberVirtualChannels", total_number_vcs); + + // Add the instance and the results + addSubInstances(input_port, number_input_ports); + addElectricalSubResults(input_port, number_input_ports); + + // Create connections + createNet("InputPort_In", makeNetIndex(0, number_bits_per_flit-1)); + createNet("InputPort_Out", makeNetIndex(0, number_bits_per_flit-1)); + + assignVirtualFanout("InputPort_In", "PipelineReg0_Out"); + portConnect(input_port, "FlitIn", "InputPort_In"); + portConnect(input_port, "CK", "CK"); + portConnect(input_port, "FlitOut", "InputPort_Out"); + assignVirtualFanin("PipelineReg1_In", "InputPort_Out"); + + return; + } + + void Router::createVirtualChannelAllocator() + {} + + void Router::createSwitchAllocator() + { + // Get parameters + unsigned int number_input_ports = getParameter("NumberInputPorts").toUInt(); + unsigned int number_output_ports = getParameter("NumberOutputPorts").toUInt(); + unsigned int total_number_vcs = getGenProperties()->get("TotalNumberVirtualChannels").toUInt(); + const String& arb_model = getParameter("SwitchAllocator->ArbiterModel"); + + // Init switch allocator model + const String& sw_allocator_name = "SwitchAllocator"; + RouterSwitchAllocator* sw_allocator = new RouterSwitchAllocator(sw_allocator_name, getTechModel()); + sw_allocator->setParameter("NumberInputPorts", number_input_ports); + sw_allocator->setParameter("NumberOutputPorts", number_output_ports); + sw_allocator->setParameter("TotalNumberVirtualChannels", total_number_vcs); + sw_allocator->setParameter("ArbiterModel", arb_model); + sw_allocator->construct(); + + // Add the instance and the results + addSubInstances(sw_allocator, 1.0); + addElectricalSubResults(sw_allocator, 1.0); + + // Create connections (currently connect CK only) + portConnect(sw_allocator, "CK", "CK"); + return; + } + + void Router::createCrossbar() + { + // Get parameters + const String& crossbar_model = getParameter("CrossbarModel"); + unsigned int number_input_ports = getParameter("NumberInputPorts").toUInt(); + unsigned int number_output_ports = getParameter("NumberOutputPorts").toUInt(); + unsigned int number_bits_per_flit = getParameter("NumberBitsPerFlit").toUInt(); + unsigned int number_input_port_outputs = getGenProperties()->get("InputPort->NumberOutputs").toUInt(); + + unsigned int number_crossbar_inputs = number_input_port_outputs * number_input_ports; + unsigned int number_crossbar_outputs = number_output_ports; + getGenProperties()->set("Crossbar->NumberInputs", number_crossbar_inputs); + getGenProperties()->set("Crossbar->NumberOutputs", number_crossbar_outputs); + + // Init crossbar model + const String& crossbar_name = "Crossbar"; + ElectricalModel* crossbar = ModelGen::createCrossbar(crossbar_model, crossbar_name, getTechModel()); + crossbar->setParameter("NumberInputs", number_crossbar_inputs); + crossbar->setParameter("NumberOutputs", number_crossbar_outputs); + crossbar->setParameter("NumberBits", number_bits_per_flit); + crossbar->setParameter("BitDuplicate", "TRUE"); + crossbar->construct(); + + unsigned int number_crossbar_selects = crossbar->getGenProperties()->get("NumberSelectsPerPort"); + getGenProperties()->set("Crossbar->NumberSelects", number_crossbar_selects); + + // Init DFF for crossbar selections + const String& crossbar_sel_dff_name = "Crossbar_Sel_DFF"; + StdCell* crossbar_sel_dff = getTechModel()->getStdCellLib()->createStdCell("DFFQ", crossbar_sel_dff_name); + crossbar_sel_dff->construct(); + + // Add instances and results + addSubInstances(crossbar, 1.0); + addElectricalSubResults(crossbar, 1.0); + + addSubInstances(crossbar_sel_dff, number_crossbar_outputs * number_crossbar_selects); + addElectricalSubResults(crossbar_sel_dff, number_crossbar_outputs * number_crossbar_selects); + + // Create connections + createNet("Crossbar_Sel_DFF_Out"); + for(unsigned int i = 0; i < number_crossbar_outputs; ++i) + { + for(unsigned int j = 0; j < number_crossbar_selects; ++j) + { + createNet(String::format("Crossbar_Sel%d_%d", i, j)); + } + createNet("Crossbar_Out" + (String)i, makeNetIndex(0, number_bits_per_flit-1)); + } + for(unsigned int i = 0; i < number_crossbar_inputs; ++i) + { + createNet("Crossbar_In" + (String)i, makeNetIndex(0, number_bits_per_flit-1)); + } + + for(unsigned int i = 0; i < number_crossbar_selects; ++i) + { + portConnect(crossbar_sel_dff, "CK", "CK"); + } + portConnect(crossbar_sel_dff, "Q", "Crossbar_Sel_DFF_Out"); + for(unsigned int i = 0; i < number_crossbar_inputs; ++i) + { + assignVirtualFanout("Crossbar_In" + (String)i, "PipelineReg1_Out"); + portConnect(crossbar, "In" + (String)i, "Crossbar_In" + (String)i); + } + for(unsigned int i = 0; i < number_crossbar_outputs; ++i) + { + for(unsigned int j = 0; j < number_crossbar_selects; ++j) + { + assignVirtualFanout(String::format("Crossbar_Sel%d_%d", i, j), "Crossbar_Sel_DFF_Out"); + portConnect(crossbar, String::format("Sel%d_%d", i, j), String::format("Crossbar_Sel%d_%d", i, j)); + } + portConnect(crossbar, "Out" + (String)i, "Crossbar_Out" + (String)i); + assignVirtualFanin("PipelineReg2_In" + (String)i, "Crossbar_Out" + (String)i); + } + + return; + } + + void Router::createPipelineReg() + { + // Get parameters + unsigned int number_input_ports = getParameter("NumberInputPorts").toUInt(); + unsigned int number_output_ports = getParameter("NumberOutputPorts").toUInt(); + unsigned int number_bits_per_flit = getParameter("NumberBitsPerFlit").toUInt(); + unsigned int number_crossbar_inputs = getGenProperties()->get("Crossbar->NumberInputs"); + + // Init pipeline reg model + // First stage: from router input to input port + const String& pipeline_reg0_name = "PipelineReg0"; + StdCell* pipeline_reg0 = getTechModel()->getStdCellLib()->createStdCell("DFFQ", pipeline_reg0_name); + pipeline_reg0->construct(); + // Second stage: from input port to crossbar + const String& pipeline_reg1_name = "PipelineReg1"; + StdCell* pipeline_reg1 = getTechModel()->getStdCellLib()->createStdCell("DFFQ", pipeline_reg1_name); + pipeline_reg1->construct(); + + // Third stage: from crossbar to router output + vector<StdCell*> pipeline_reg2s(number_output_ports, (StdCell*)NULL); + vector<String> pipeline_reg2_names(number_output_ports, ""); + for(unsigned int i = 0; i < number_output_ports; ++i) + { + pipeline_reg2_names[i] = "PipelineReg2_" + (String)i; + pipeline_reg2s[i] = getTechModel()->getStdCellLib()->createStdCell("DFFQ", pipeline_reg2_names[i]); + pipeline_reg2s[i]->construct(); + } + + // Add instances and results + addSubInstances(pipeline_reg0, number_input_ports * number_bits_per_flit); + addElectricalSubResults(pipeline_reg0, number_input_ports * number_bits_per_flit); + + addSubInstances(pipeline_reg1, number_crossbar_inputs * number_bits_per_flit); + addElectricalSubResults(pipeline_reg1, number_crossbar_inputs * number_bits_per_flit); + + for(unsigned int i = 0; i < number_output_ports; ++i) + { + addSubInstances(pipeline_reg2s[i], number_bits_per_flit); + addElectricalSubResults(pipeline_reg2s[i], number_bits_per_flit); + } + + // Create data connections + for(unsigned int i = 0; i < number_input_ports; ++i) + { + assignVirtualFanin("PipelineReg0_In", "FlitIn" + (String)i); + } + portConnect(pipeline_reg0, "D", "PipelineReg0_In"); + portConnect(pipeline_reg0, "Q", "PipelineReg0_Out"); + portConnect(pipeline_reg1, "D", "PipelineReg1_In"); + portConnect(pipeline_reg1, "Q", "PipelineReg1_Out"); + for(unsigned int i = 0; i < number_output_ports; ++i) + { + portConnect(pipeline_reg2s[i], "D", "PipelineReg2_In" + (String)i); + portConnect(pipeline_reg2s[i], "Q", "PipelineReg2_Out" + (String)i); + assignVirtualFanout("FlitOut" + (String)i, "PipelineReg2_Out" + (String)i); + } + + // Create CK connections + for(unsigned int n = 0; n < number_bits_per_flit; ++n) + { + for(unsigned int i = 0; i < number_input_ports; ++i) + { + portConnect(pipeline_reg0, "CK", "CK"); + } + for(unsigned int i = 0; i < number_crossbar_inputs; ++i) + { + portConnect(pipeline_reg1, "CK", "CK"); + } + for(unsigned int i = 0; i < number_output_ports; ++i) + { + portConnect(pipeline_reg2s[i], "CK", "CK"); + } + } + return; + } + + void Router::createClockTree() + { + // Get parameters + const String& clock_tree_model = getParameter("ClockTreeModel"); + const String& clock_tree_number_levels = getParameter("ClockTree->NumberLevels"); + const String& clock_tree_wire_layer = getParameter("ClockTree->WireLayer"); + const String& clock_tree_wire_width_multiplier = getParameter("ClockTree->WireWidthMultiplier"); + const String& clock_tree_wire_spacing_multiplier = getParameter("ClockTree->WireSpacingMultiplier"); + + // Init clock tree model + const String& clock_tree_name = "ClockTree"; + ElectricalModel* clock_tree = (ElectricalModel*)ModelGen::createModel(clock_tree_model, clock_tree_name, getTechModel()); + clock_tree->setParameter("NumberLevels", clock_tree_number_levels); + clock_tree->setParameter("NumberBits", 1); + clock_tree->setParameter("WireLayer", clock_tree_wire_layer); + clock_tree->setParameter("WireWidthMultiplier", clock_tree_wire_width_multiplier); + clock_tree->setParameter("WireSpacingMultiplier", clock_tree_wire_spacing_multiplier); + clock_tree->construct(); + + // Add instances and results + addSubInstances(clock_tree, 1.0); + addElectricalSubResults(clock_tree, 1.0); + + return; + } +} // namespace DSENT + diff --git a/ext/dsent/model/electrical/router/Router.h b/ext/dsent/model/electrical/router/Router.h new file mode 100644 index 000000000..c2c1df3bc --- /dev/null +++ b/ext/dsent/model/electrical/router/Router.h @@ -0,0 +1,46 @@ +#ifndef __DSENT_MODEL_ELECTRICAL_ROUTER_ROUTER_H__ +#define __DSENT_MODEL_ELECTRICAL_ROUTER_ROUTER_H__ + +#include "util/CommonType.h" +#include "model/ElectricalModel.h" + +namespace DSENT +{ + /** \class Router + * \param Input ports: In[0-9]* + * \param Output ports: Out[0-9]* + */ + class Router : public ElectricalModel + { + public: + Router(const String& instance_name_, const TechModel* tech_model_); + virtual ~Router(); + + public: + // Set a list of properties' name needed to construct model + void initParameters(); + // Set a list of properties' name needed to construct model + void initProperties(); + + // Clone and return a new instance + virtual Router* clone() const; + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void propagateTransitionInfo(); + + private: + void createRouterInputPort(); + void createVirtualChannelAllocator(); + void createSwitchAllocator(); + void createCrossbar(); + void createClockTree(); + void createPipelineReg(); + + }; // class Router +} // namespace DSENT + +#endif // __DSENT_MODEL_ELECTRICAL_ROUTER_ROUTER_H__ + diff --git a/ext/dsent/model/electrical/router/RouterInputPort.cc b/ext/dsent/model/electrical/router/RouterInputPort.cc new file mode 100644 index 000000000..b698d3d80 --- /dev/null +++ b/ext/dsent/model/electrical/router/RouterInputPort.cc @@ -0,0 +1,201 @@ +#include "model/electrical/router/RouterInputPort.h" + +#include <cmath> +#include <vector> + +#include "model/PortInfo.h" +#include "model/EventInfo.h" +#include "model/TransitionInfo.h" +#include "model/ModelGen.h" +#include "model/std_cells/StdCellLib.h" +#include "model/std_cells/StdCell.h" + +namespace DSENT +{ + using std::ceil; + using std::vector; + using LibUtil::castStringVector; + + RouterInputPort::RouterInputPort(const String& instance_name_, const TechModel* tech_model_) + : ElectricalModel(instance_name_, tech_model_) + { + initParameters(); + initProperties(); + } + + RouterInputPort::~RouterInputPort() + {} + + void RouterInputPort::initParameters() + { + addParameterName("NumberVirtualNetworks"); + addParameterName("NumberVirtualChannelsPerVirtualNetwork"); + addParameterName("NumberBuffersPerVirtualChannel"); + addParameterName("NumberBitsPerFlit"); + addParameterName("BufferModel"); + return; + } + + void RouterInputPort::initProperties() + { + return; + } + + RouterInputPort* RouterInputPort::clone() const + { + // TODO + return NULL; + } + + void RouterInputPort::constructModel() + { + // Get parameters + unsigned int number_vns = getParameter("NumberVirtualNetworks").toUInt(); + const vector<unsigned int>& number_vcs_per_vn_vector = castStringVector<unsigned int>(getParameter("NumberVirtualChannelsPerVirtualNetwork").split("[,]")); + const vector<unsigned int>& number_bufs_per_vc_vector = castStringVector<unsigned int>(getParameter("NumberBuffersPerVirtualChannel").split("[,]")); + unsigned int number_bits_per_flit = getParameter("NumberBitsPerFlit").toUInt(); + const String& buffer_model = getParameter("BufferModel"); + + ASSERT(number_vns > 0, "[Error] " + getInstanceName() + + " -> Number of virtual networks must be > 0!"); + ASSERT(number_vcs_per_vn_vector.size() == number_vns, "[Error] " + getInstanceName() + + " -> Expecting " + (String)number_vns + " number of vcs, got " + + getParameter("NumberVirtualChannelsPerVirtualNetwork")); + for(unsigned int i = 0; i < number_vns; ++i) + { + ASSERT(number_vcs_per_vn_vector[i] > 0, "[Error] " + getInstanceName() + + " -> Number of virtual channels per virtual network must be > 0!"); + } + ASSERT(number_bufs_per_vc_vector.size() == number_vns, "[Error] " + getInstanceName() + + " -> Expecting " + (String)number_vns + " number of bufs per vc, got " + + getParameter("NumberBuffersPerVirtualChannel")); + for(unsigned int i = 0; i < number_vns; ++i) + { + ASSERT(number_bufs_per_vc_vector[i] > 0, "[Error] " + getInstanceName() + + " -> Number of buffers per virtual channel must be > 0!"); + } + ASSERT(number_bits_per_flit > 0, "[Error] " + getInstanceName() + + " -> Number of bits per buffer must be > 0!"); + + // Calculate total number of buffers needed in the RAM + unsigned int total_number_vcs = 0; + unsigned int total_number_bufs = 0; + for(unsigned int i = 0; i < number_vns; ++i) + { + total_number_vcs += number_vcs_per_vn_vector[i]; + total_number_bufs += number_vcs_per_vn_vector[i] * number_bufs_per_vc_vector[i]; + } + unsigned int number_addr_bits = (unsigned int)ceil(log2(total_number_bufs)); + + getGenProperties()->set("TotalNumberVirtualChannels", total_number_vcs); + getGenProperties()->set("TotalNumberBuffers", total_number_bufs); + getGenProperties()->set("NumberAddressBits", number_addr_bits); + getGenProperties()->set("NumberOutputs", 1); + + createInputPort("CK"); + createInputPort("FlitIn", makeNetIndex(0, number_bits_per_flit-1)); + createOutputPort("FlitOut", makeNetIndex(0, number_bits_per_flit-1)); + + // Create energy, power, and area results + createElectricalResults(); + getEventInfo("Idle")->setStaticTransitionInfos(); + getEventInfo("Idle")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0)); + + addEventResult(new Result("ReadBuffer")); + addEventResult(new Result("WriteBuffer")); + + // Init RAM + const String& ram_name = "RAM"; + ElectricalModel* ram = ModelGen::createRAM(buffer_model, ram_name, getTechModel()); + ram->setParameter("NumberEntries", total_number_bufs); + ram->setParameter("NumberBits", number_bits_per_flit); + ram->construct(); + + // Init DFF for read address + vector<String> rd_addr_dff_names(number_addr_bits, ""); + vector<StdCell*> rd_addr_dffs(number_addr_bits, NULL); + for(unsigned int i = 0; i < number_addr_bits; ++i) + { + rd_addr_dff_names[i] = "RDAddr_DFF" + (String)i; + rd_addr_dffs[i] = getTechModel()->getStdCellLib()->createStdCell("DFFQ", rd_addr_dff_names[i]); + rd_addr_dffs[i]->construct(); + } + + // Connect RDAddr_DFFs + for(unsigned int i = 0; i < number_addr_bits; ++i) + { + createNet("RDAddr_DFF_Out" + (String)i); + + portConnect(rd_addr_dffs[i], "CK", "CK"); + portConnect(rd_addr_dffs[i], "Q", "RDAddr_DFF_Out" + (String)i); + } + + // Connect RAM + portConnect(ram, "In", "FlitIn"); + for(unsigned int i = 0; i < number_addr_bits; ++i) + { + portConnect(ram, "WRAddr" + (String)i, "FlitIn", makeNetIndex(i)); + portConnect(ram, "RDAddr" + (String)i, "RDAddr_DFF_Out" + (String)i); + } + portConnect(ram, "WE", "FlitIn", makeNetIndex(number_bits_per_flit-1)); + portConnect(ram, "CK", "CK"); + portConnect(ram, "Out", "FlitOut"); + + // Add area, power, event results + for(unsigned int i = 0; i < number_addr_bits; ++i) + { + addSubInstances(rd_addr_dffs[i], number_addr_bits); + addElectricalSubResults(rd_addr_dffs[i], number_addr_bits); + } + addSubInstances(ram, 1.0); + addElectricalSubResults(ram, 1.0); + + getEventResult("WriteBuffer")->addSubResult(ram->getEventResult("Write"), ram_name, 1.0); + + for(unsigned int i = 0; i < number_addr_bits; ++i) + { + getEventResult("ReadBuffer")->addSubResult(rd_addr_dffs[i]->getEventResult("DFFD"), rd_addr_dff_names[i], number_addr_bits); + getEventResult("ReadBuffer")->addSubResult(rd_addr_dffs[i]->getEventResult("DFFQ"), rd_addr_dff_names[i], number_addr_bits); + getEventResult("ReadBuffer")->addSubResult(rd_addr_dffs[i]->getEventResult("CK"), rd_addr_dff_names[i], number_addr_bits); + } + getEventResult("ReadBuffer")->addSubResult(ram->getEventResult("Read"), ram_name, 1.0); + + return; + } + + void RouterInputPort::propagateTransitionInfo() + { + // Update probability and activity + unsigned int number_addr_bits = getGenProperties()->get("NumberAddressBits").toUInt(); + + vector<ElectricalModel*> rd_addr_dffs(number_addr_bits, NULL); + for(unsigned int i = 0; i < number_addr_bits; ++i) + { + rd_addr_dffs[i] = (ElectricalModel*)getSubInstance("RDAddr_DFF" + (String)i); + assignPortTransitionInfo(rd_addr_dffs[i], "D", TransitionInfo()); + propagatePortTransitionInfo(rd_addr_dffs[i], "CK", "CK"); + rd_addr_dffs[i]->use(); + } + + ElectricalModel* ram = (ElectricalModel*)getSubInstance("RAM"); + + // Setup default transition info + const String& current_event = getGenProperties()->get("UseModelEvent"); + if(current_event != "Idle") + { + propagatePortTransitionInfo(ram, "In", "FlitIn"); + propagatePortTransitionInfo(ram, "CK", "CK"); + assignPortTransitionInfo(ram, "WE", TransitionInfo(0.0, 0.0, 1.0)); + for(unsigned int i = 0; i < number_addr_bits; ++i) + { + assignPortTransitionInfo(ram, "WRAddr" + (String)i, TransitionInfo(0.25, 0.25, 0.25)); + assignPortTransitionInfo(ram, "RDAddr" + (String)i, TransitionInfo(0.25, 0.25, 0.25)); + } + } + ram->use(); + // Set output probability + propagatePortTransitionInfo("FlitOut", ram, "Out"); + return; + } +} // namespace DSENT + diff --git a/ext/dsent/model/electrical/router/RouterInputPort.h b/ext/dsent/model/electrical/router/RouterInputPort.h new file mode 100644 index 000000000..1d326a5cf --- /dev/null +++ b/ext/dsent/model/electrical/router/RouterInputPort.h @@ -0,0 +1,33 @@ +#ifndef __DSENT_MODEL_ELECTRICAL_ROUTER_ROUTER_INPUT_PORT_H__ +#define __DSENT_MODEL_ELECTRICAL_ROUTER_ROUTER_INPUT_PORT_H__ + +#include "util/CommonType.h" +#include "model/ElectricalModel.h" + +namespace DSENT +{ + class RouterInputPort : public ElectricalModel + { + public: + RouterInputPort(const String& instance_name_, const TechModel* tech_model_); + virtual ~RouterInputPort(); + + public: + // Set a list of properties' name needed to construct model + void initParameters(); + // Set a list of properties' name needed to construct model + void initProperties(); + + // Clone and return a new instance + virtual RouterInputPort* clone() const; + + protected: + // Build the model + virtual void constructModel(); + virtual void propagateTransitionInfo(); + + }; // class RouterInputPort +} // namespace DSENT + +#endif // __DSENT_MODEL_ELECTRICAL_ROUTER_ROUTER_INPUT_PORT_H__ + diff --git a/ext/dsent/model/electrical/router/RouterSwitchAllocator.cc b/ext/dsent/model/electrical/router/RouterSwitchAllocator.cc new file mode 100644 index 000000000..92e5431b1 --- /dev/null +++ b/ext/dsent/model/electrical/router/RouterSwitchAllocator.cc @@ -0,0 +1,199 @@ +#include "model/electrical/router/RouterSwitchAllocator.h" + +#include "model/PortInfo.h" +#include "model/EventInfo.h" +#include "model/TransitionInfo.h" +#include "model/ModelGen.h" +#include "model/std_cells/StdCell.h" +#include "model/std_cells/StdCellLib.h" + +namespace DSENT +{ + RouterSwitchAllocator::RouterSwitchAllocator(const String& instance_name_, const TechModel* tech_model_) + : ElectricalModel(instance_name_, tech_model_) + { + initParameters(); + initProperties(); + } + + RouterSwitchAllocator::~RouterSwitchAllocator() + {} + + void RouterSwitchAllocator::initParameters() + { + addParameterName("NumberInputPorts"); + addParameterName("NumberOutputPorts"); + addParameterName("TotalNumberVirtualChannels"); + addParameterName("ArbiterModel"); + return; + } + + void RouterSwitchAllocator::initProperties() + {} + + RouterSwitchAllocator* RouterSwitchAllocator::clone() const + { + // TODO + return NULL; + } + + void RouterSwitchAllocator::constructModel() + { + // Get parameters + unsigned int number_input_ports = getParameter("NumberInputPorts").toUInt(); + unsigned int number_output_ports = getParameter("NumberOutputPorts").toUInt(); + unsigned int total_number_vcs = getParameter("TotalNumberVirtualChannels").toUInt(); + const String& arb_model = getParameter("ArbiterModel"); + + ASSERT(number_input_ports > 0, "[Error] " + getInstanceName() + + " -> Number of input ports must be > 0!"); + ASSERT(number_output_ports > 0, "[Error] " + getInstanceName() + + " -> Number of output ports must be > 0!"); + ASSERT(total_number_vcs > 0, "[Error] " + getInstanceName() + + " -> Total number of virtual channels must be > 0!"); + + unsigned int stage1_number_requests = total_number_vcs; + unsigned int number_stage1_arbiters = number_input_ports; + unsigned int stage2_number_requests = number_input_ports; + unsigned int number_stage2_arbiters = number_output_ports; + + getGenProperties()->set("NumberStage1Arbiters", number_stage1_arbiters); + getGenProperties()->set("Stage1->NumberRequests", stage1_number_requests); + getGenProperties()->set("NumberStage2Arbiters", number_stage2_arbiters); + getGenProperties()->set("Stage2->NumberRequests", stage2_number_requests); + + // Create ports + createInputPort("CK"); + for(unsigned int i = 0; i < number_stage1_arbiters; ++i) + { + for(unsigned int j = 0; j < stage1_number_requests; ++j) + { + createInputPort(String::format("Stage1Arb%d->Request%d", i, j)); + createInputPort(String::format("Stage1Arb%d->Grant%d", i, j)); + } + } + for(unsigned int i = 0; i < number_stage2_arbiters; ++i) + { + for(unsigned int j = 0; j < stage2_number_requests; ++j) + { + createInputPort(String::format("Stage2Arb%d->Request%d", i, j)); + createInputPort(String::format("Stage2Arb%d->Grant%d", i, j)); + } + } + + // Create area, power, and event results + createElectricalResults(); + getEventInfo("Idle")->setStaticTransitionInfos(); + getEventInfo("Idle")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0)); + + createElectricalEventResult("ArbitrateStage1"); + getEventInfo("ArbitrateStage1")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0)); + createElectricalEventResult("ArbitrateStage2"); + getEventInfo("ArbitrateStage2")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0)); + + // Init Stage1 arbiter + vector<String> stage1_arb_dff_names(stage1_number_requests, ""); + vector<StdCell*> stage1_arb_dffs(stage1_number_requests, NULL); + for(unsigned int i = 0; i < stage1_number_requests; ++i) + { + stage1_arb_dff_names[i] = "Stage1ArbDFF" + (String)i; + stage1_arb_dffs[i] = getTechModel()->getStdCellLib()->createStdCell("DFFQ", stage1_arb_dff_names[i]); + stage1_arb_dffs[i]->construct(); + } + const String& stage1_arb_name = "Stage1Arb"; + ElectricalModel* stage1_arb = (ElectricalModel*)ModelGen::createModel(arb_model, stage1_arb_name, getTechModel()); + stage1_arb->setParameter("NumberRequests", stage1_number_requests); + stage1_arb->construct(); + + // Init stage2 arbiter + vector<String> stage2_arb_dff_names(stage2_number_requests, ""); + vector<StdCell*> stage2_arb_dffs(stage2_number_requests, NULL); + for(unsigned int i = 0; i < stage2_number_requests; ++i) + { + stage2_arb_dff_names[i] = "Stage2ArbDFF" + (String)i; + stage2_arb_dffs[i] = getTechModel()->getStdCellLib()->createStdCell("DFFQ", stage2_arb_dff_names[i]); + stage2_arb_dffs[i]->construct(); + } + const String& stage2_arb_name = "Stage2Arb"; + ElectricalModel* stage2_arb = (ElectricalModel*)ModelGen::createModel(arb_model, stage2_arb_name, getTechModel()); + stage2_arb->setParameter("NumberRequests", stage2_number_requests); + stage2_arb->construct(); + + // Connect ports + for(unsigned int i = 0; i < stage1_number_requests; ++i) + { + const String& dff_in_name = "Stage1Arb_DFF_In" + (String)i; + const String& req_name = "Stage1Arb->Request" + (String)i; + const String& grant_name = "Stage1Arb->Grant" + (String)i; + createNet(dff_in_name); + createNet(req_name); + createNet(grant_name); + portConnect(stage1_arb_dffs[i], "D", dff_in_name); + portConnect(stage1_arb_dffs[i], "CK", "CK"); + portConnect(stage1_arb_dffs[i], "Q", req_name); + portConnect(stage1_arb, "Request" + (String)i, req_name); + portConnect(stage1_arb, "Grant" + (String)i, grant_name); + for(unsigned int j = 0; j < number_stage1_arbiters; ++j) + { + assignVirtualFanin(dff_in_name, String::format("Stage1Arb%d->Request%d", j, i)); + assignVirtualFanout(String::format("Stage1Arb%d->Grant%d", j, i), grant_name); + } + } + for(unsigned int i = 0; i < stage2_number_requests; ++i) + { + const String& dff_in_name = "Stage2Arb_DFF_In" + (String)i; + const String& req_name = "Stage2Arb->Request" + (String)i; + const String& grant_name = "Stage2Arb->Grant" + (String)i; + createNet(dff_in_name); + createNet(req_name); + createNet(grant_name); + portConnect(stage2_arb_dffs[i], "D", dff_in_name); + portConnect(stage2_arb_dffs[i], "CK", "CK"); + portConnect(stage2_arb_dffs[i], "Q", req_name); + portConnect(stage2_arb, "Request" + (String)i, req_name); + portConnect(stage2_arb, "Grant" + (String)i, grant_name); + for(unsigned int j = 0; j < number_stage2_arbiters; ++j) + { + assignVirtualFanin(dff_in_name, String::format("Stage2Arb%d->Request%d", j, i)); + assignVirtualFanout(String::format("Stage2Arb%d->Grant%d", j, i), grant_name); + } + } + + // Add sub components + for(unsigned int i = 0; i < stage1_number_requests; ++i) + { + addSubInstances(stage1_arb_dffs[i], 1.0); + addElectricalSubResults(stage1_arb_dffs[i], 1.0); + } + addSubInstances(stage1_arb, number_stage1_arbiters); + addElectricalSubResults(stage1_arb, number_stage1_arbiters); + for(unsigned int i = 0; i < stage2_number_requests; ++i) + { + addSubInstances(stage2_arb_dffs[i], 1.0); + addElectricalSubResults(stage2_arb_dffs[i], 1.0); + } + addSubInstances(stage2_arb, number_stage2_arbiters); + addElectricalSubResults(stage2_arb, number_stage2_arbiters); + + // Update stage1 arb arbitrate + getEventResult("ArbitrateStage1")->addSubResult(stage1_arb->getEventResult("Arbitrate"), stage1_arb_name, 1.0); + + // Update stage2 arb arbitrate + getEventResult("ArbitrateStage2")->addSubResult(stage2_arb->getEventResult("Arbitrate"), stage2_arb_name, 1.0); + return; + } + + void RouterSwitchAllocator::propagateTransitionInfo() + { + ElectricalModel* stage1_arb = (ElectricalModel*)getSubInstance("Stage1Arb"); + stage1_arb->applyTransitionInfo("Arbitrate"); + stage1_arb->use(); + + ElectricalModel* stage2_arb = (ElectricalModel*)getSubInstance("Stage2Arb"); + stage2_arb->applyTransitionInfo("Arbitrate"); + stage2_arb->use(); + + return; + } +} // namespace DSENT + diff --git a/ext/dsent/model/electrical/router/RouterSwitchAllocator.h b/ext/dsent/model/electrical/router/RouterSwitchAllocator.h new file mode 100644 index 000000000..8b18e199f --- /dev/null +++ b/ext/dsent/model/electrical/router/RouterSwitchAllocator.h @@ -0,0 +1,33 @@ +#ifndef __DSENT_MODEL_ELECTRICAL_ROUTER_ROUTER_SWITCH_ALLOCATOR_H__ +#define __DSENT_MODEL_ELECTRICAL_ROUTER_ROUTER_SWITCH_ALLOCATOR_H__ + +#include "util/CommonType.h" +#include "model/ElectricalModel.h" + +namespace DSENT +{ + class RouterSwitchAllocator : public ElectricalModel + { + public: + RouterSwitchAllocator(const String& instance_name_, const TechModel* tech_model_); + virtual ~RouterSwitchAllocator(); + + public: + // Set a list of properties' name needed to construct model + void initParameters(); + // Set a list of properties' name needed to construct model + void initProperties(); + + // Clone and return a new instance + virtual RouterSwitchAllocator* clone() const; + + protected: + // Build the model + virtual void constructModel(); + virtual void propagateTransitionInfo(); + + }; // RouterSwitchAllocator +} // namespace DSENT + +#endif // __DSENT_MODEL_ELECTRICAL_ROUTER_ROUTER_SWITCH_ALLOCATOR_H__ + diff --git a/ext/dsent/model/network/ElectricalClos.cc b/ext/dsent/model/network/ElectricalClos.cc new file mode 100644 index 000000000..94781d886 --- /dev/null +++ b/ext/dsent/model/network/ElectricalClos.cc @@ -0,0 +1,489 @@ +#include "model/network/ElectricalClos.h" + +#include <cmath> + +#include "model/ModelGen.h" +#include "model/timing_graph/ElectricalTimingTree.h" +#include "model/timing_graph/ElectricalNet.h" + +namespace DSENT +{ + using std::sqrt; + + ElectricalClos::ElectricalClos(const String& instance_name_, const TechModel* tech_model_) + : ElectricalModel(instance_name_, tech_model_) + { + initParameters(); + initProperties(); + } + + ElectricalClos::~ElectricalClos() + {} + + void ElectricalClos::initParameters() + { + // Frequency + addParameterName("Frequency"); + // Physical Parameters + addParameterName("NumberInputSites"); + addParameterName("NumberOutputSites"); + addParameterName("NumberBitsPerFlit"); + // Number of each type of routers + addParameterName("NumberIngressRouters"); + addParameterName("NumberMiddleRouters"); + addParameterName("NumberEgressRouters"); + // Router parameters + addParameterName("Router->NumberVirtualNetworks"); + addParameterName("Router->NumberVirtualChannelsPerVirtualNetwork"); + addParameterName("Router->NumberBuffersPerVirtualChannel"); + addParameterName("Router->InputPort->BufferModel"); + addParameterName("Router->CrossbarModel"); + addParameterName("Router->SwitchAllocator->ArbiterModel"); + addParameterName("Router->ClockTreeModel"); + addParameterName("Router->ClockTree->NumberLevels"); + addParameterName("Router->ClockTree->WireLayer"); + addParameterName("Router->ClockTree->WireWidthMultiplier"); + addParameterName("Router->ClockTree->WireSpacingMultiplier", 3.0); + // Link parameters + addParameterName("Link->WireLayer"); + addParameterName("Link->WireWidthMultiplier"); + addParameterName("Link->WireSpacingMultiplier"); + return; + } + + void ElectricalClos::initProperties() + { + addPropertyName("InputSitePitch"); + addPropertyName("OutputSitePitch"); + return; + } + + ElectricalClos* ElectricalClos::clone() const + { + // TODO + return NULL; + } + + void ElectricalClos::constructModel() + { + // Get input parameters + unsigned int number_input_sites = getParameter("NumberInputSites").toUInt(); + unsigned int number_output_sites = getParameter("NumberOutputSites").toUInt(); + unsigned int number_bits_per_flit = getParameter("NumberBitsPerFlit").toUInt(); + unsigned int number_ingress_routers = getParameter("NumberIngressRouters").toUInt(); + unsigned int number_middle_routers = getParameter("NumberMiddleRouters").toUInt(); + unsigned int number_egress_routers = getParameter("NumberEgressRouters").toUInt(); + + ASSERT(number_input_sites > 0, "[Error] " + getInstanceName() + + " -> Number of input sites must be > 0!"); + ASSERT(number_output_sites > 0, "[Error] " + getInstanceName() + + " -> Number of output sites must be > 0!"); + ASSERT(number_bits_per_flit > 0, "[Error] " + getInstanceName() + + " -> Number of bits per flit must be > 0!"); + ASSERT(number_ingress_routers > 0, "[Error] " + getInstanceName() + + " -> Number of ingress routers must be > 0!"); + ASSERT(number_middle_routers > 0, "[Error] " + getInstanceName() + + " -> Number of middle routers must be > 0!"); + ASSERT(number_egress_routers > 0, "[Error] " + getInstanceName() + + " -> Number of egress routers must be > 0!"); + + // Get input parameters that will be forwarded to the sub instances + const String& router_number_vns = getParameter("Router->NumberVirtualNetworks"); + const String& router_number_vcs_per_vn = getParameter("Router->NumberVirtualChannelsPerVirtualNetwork"); + const String& router_number_bufs_per_vc = getParameter("Router->NumberBuffersPerVirtualChannel"); + const String& router_buffer_model = getParameter("Router->InputPort->BufferModel"); + const String& router_crossbar_model = getParameter("Router->CrossbarModel"); + const String& link_wire_layer = getParameter("Link->WireLayer"); + const String& link_wire_width_multiplier = getParameter("Link->WireWidthMultiplier"); + const String& link_wire_spacing_multiplier = getParameter("Link->WireSpacingMultiplier"); + + // Calculate properties from input parameters + unsigned int ingress_router_number_input_ports = number_input_sites / number_ingress_routers; + unsigned int ingress_router_number_output_ports = number_middle_routers; + unsigned int middle_router_number_input_ports = number_ingress_routers; + unsigned int middle_router_number_output_ports = number_egress_routers; + unsigned int egress_router_number_input_ports = number_middle_routers; + unsigned int egress_router_number_output_ports = number_output_sites / number_egress_routers; + unsigned int number_input_to_ingress_links = number_input_sites; + unsigned int number_ingress_to_middle_links = number_ingress_routers * number_middle_routers; + unsigned int number_middle_to_egress_links = number_middle_routers * number_egress_routers; + unsigned int number_egress_to_output_links = number_output_sites; + + getGenProperties()->set("NumberInputSitesPerIngressRouter", ingress_router_number_input_ports); + getGenProperties()->set("NumberOutputSitesPerEgressRouter", egress_router_number_output_ports); + getGenProperties()->set("IngressRouter->NumberInputPorts", ingress_router_number_input_ports); + getGenProperties()->set("IngressRouter->NumberOutputPorts", ingress_router_number_output_ports); + getGenProperties()->set("MiddleRouter->NumberInputPorts", middle_router_number_input_ports); + getGenProperties()->set("MiddleRouter->NumberOutputPorts", middle_router_number_output_ports); + getGenProperties()->set("EgressRouter->NumberInputPorts", egress_router_number_input_ports); + getGenProperties()->set("EgressRouter->NumberOutputPorts", egress_router_number_output_ports); + + // Create ports + createInputPort("CK"); + + // Init ingress router + ElectricalModel* ingress_router = (ElectricalModel*)ModelGen::createModel("Router", "IngressRouter", getTechModel()); + ingress_router->setParameter("NumberInputPorts", ingress_router_number_input_ports); + ingress_router->setParameter("NumberOutputPorts", ingress_router_number_output_ports); + ingress_router->setParameter("NumberVirtualNetworks", router_number_vns); + ingress_router->setParameter("NumberVirtualChannelsPerVirtualNetwork", router_number_vcs_per_vn); + ingress_router->setParameter("NumberBuffersPerVirtualChannel", router_number_bufs_per_vc); + ingress_router->setParameter("NumberBitsPerFlit", number_bits_per_flit); + ingress_router->setParameter("InputPort->BufferModel", router_buffer_model); + ingress_router->setParameter("CrossbarModel", router_crossbar_model); + ingress_router->setParameter("SwitchAllocator->ArbiterModel", getParameter("Router->SwitchAllocator->ArbiterModel")); + ingress_router->setParameter("ClockTreeModel", getParameter("Router->ClockTreeModel")); + ingress_router->setParameter("ClockTree->NumberLevels", getParameter("Router->ClockTree->NumberLevels")); + ingress_router->setParameter("ClockTree->WireLayer", getParameter("Router->ClockTree->WireLayer")); + ingress_router->setParameter("ClockTree->WireWidthMultiplier", getParameter("Router->ClockTree->WireWidthMultiplier")); + ingress_router->setParameter("ClockTree->WireSpacingMultiplier", getParameter("Router->ClockTree->WireSpacingMultiplier")); + ingress_router->construct(); + // Init middle routers + ElectricalModel* middle_router = (ElectricalModel*)ModelGen::createModel("Router", "MiddleRouter", getTechModel()); + middle_router->setParameter("NumberInputPorts", middle_router_number_input_ports); + middle_router->setParameter("NumberOutputPorts", middle_router_number_output_ports); + middle_router->setParameter("NumberVirtualNetworks", router_number_vns); + middle_router->setParameter("NumberVirtualChannelsPerVirtualNetwork", router_number_vcs_per_vn); + middle_router->setParameter("NumberBuffersPerVirtualChannel", router_number_bufs_per_vc); + middle_router->setParameter("NumberBitsPerFlit", number_bits_per_flit); + middle_router->setParameter("InputPort->BufferModel", router_buffer_model); + middle_router->setParameter("CrossbarModel", router_crossbar_model); + middle_router->setParameter("SwitchAllocator->ArbiterModel", getParameter("Router->SwitchAllocator->ArbiterModel")); + middle_router->setParameter("ClockTreeModel", getParameter("Router->ClockTreeModel")); + middle_router->setParameter("ClockTree->NumberLevels", getParameter("Router->ClockTree->NumberLevels")); + middle_router->setParameter("ClockTree->WireLayer", getParameter("Router->ClockTree->WireLayer")); + middle_router->setParameter("ClockTree->WireWidthMultiplier", getParameter("Router->ClockTree->WireWidthMultiplier")); + middle_router->setParameter("ClockTree->WireSpacingMultiplier", getParameter("Router->ClockTree->WireSpacingMultiplier")); + middle_router->construct(); + // Init egress routers + ElectricalModel* egress_router = (ElectricalModel*)ModelGen::createModel("Router", "EgressRouter", getTechModel()); + egress_router->setParameter("NumberInputPorts", egress_router_number_input_ports); + egress_router->setParameter("NumberOutputPorts", egress_router_number_output_ports); + egress_router->setParameter("NumberVirtualNetworks", router_number_vns); + egress_router->setParameter("NumberVirtualChannelsPerVirtualNetwork", router_number_vcs_per_vn); + egress_router->setParameter("NumberBuffersPerVirtualChannel", router_number_bufs_per_vc); + egress_router->setParameter("NumberBitsPerFlit", number_bits_per_flit); + egress_router->setParameter("InputPort->BufferModel", router_buffer_model); + egress_router->setParameter("CrossbarModel", router_crossbar_model); + egress_router->setParameter("SwitchAllocator->ArbiterModel", getParameter("Router->SwitchAllocator->ArbiterModel")); + egress_router->setParameter("ClockTreeModel", getParameter("Router->ClockTreeModel")); + egress_router->setParameter("ClockTree->NumberLevels", getParameter("Router->ClockTree->NumberLevels")); + egress_router->setParameter("ClockTree->WireLayer", getParameter("Router->ClockTree->WireLayer")); + egress_router->setParameter("ClockTree->WireWidthMultiplier", getParameter("Router->ClockTree->WireWidthMultiplier")); + egress_router->setParameter("ClockTree->WireSpacingMultiplier", getParameter("Router->ClockTree->WireSpacingMultiplier")); + egress_router->construct(); + // Init input to ingress link + ElectricalModel* input_to_ingress_link = (ElectricalModel*)ModelGen::createModel("RepeatedLink", "InputToIngressLink", getTechModel()); + input_to_ingress_link->setParameter("NumberBits", number_bits_per_flit); + input_to_ingress_link->setParameter("WireLayer", link_wire_layer); + input_to_ingress_link->setParameter("WireWidthMultiplier", link_wire_width_multiplier); + input_to_ingress_link->setParameter("WireSpacingMultiplier", link_wire_spacing_multiplier); + input_to_ingress_link->construct(); + // Init ingress to middle link + ElectricalModel* ingress_to_middle_link = (ElectricalModel*)ModelGen::createModel("RepeatedLink", "IngressToMiddleLink", getTechModel()); + ingress_to_middle_link->setParameter("NumberBits", number_bits_per_flit); + ingress_to_middle_link->setParameter("WireLayer", link_wire_layer); + ingress_to_middle_link->setParameter("WireWidthMultiplier", link_wire_width_multiplier); + ingress_to_middle_link->setParameter("WireSpacingMultiplier", link_wire_spacing_multiplier); + ingress_to_middle_link->construct(); + // Init middle to egress link + ElectricalModel* middle_to_egress_link = (ElectricalModel*)ModelGen::createModel("RepeatedLink", "MiddleToEgressLink", getTechModel()); + middle_to_egress_link->setParameter("NumberBits", number_bits_per_flit); + middle_to_egress_link->setParameter("WireLayer", link_wire_layer); + middle_to_egress_link->setParameter("WireWidthMultiplier", link_wire_width_multiplier); + middle_to_egress_link->setParameter("WireSpacingMultiplier", link_wire_spacing_multiplier); + middle_to_egress_link->construct(); + // Init egress to output link + ElectricalModel* egress_to_output_link = (ElectricalModel*)ModelGen::createModel("RepeatedLink", "EgressToOutputLink", getTechModel()); + egress_to_output_link->setParameter("NumberBits", number_bits_per_flit); + egress_to_output_link->setParameter("WireLayer", link_wire_layer); + egress_to_output_link->setParameter("WireWidthMultiplier", link_wire_width_multiplier); + egress_to_output_link->setParameter("WireSpacingMultiplier", link_wire_spacing_multiplier); + egress_to_output_link->construct(); + + // Connect ports + createNet("InputToIngressLink_Out", makeNetIndex(0, number_bits_per_flit-1)); + createNet("InputToIngressLink_In", makeNetIndex(0, number_bits_per_flit-1)); + portConnect(input_to_ingress_link, "In", "InputToIngressLink_In"); + portConnect(input_to_ingress_link, "Out", "InputToIngressLink_Out"); + + createNet("IngressToMiddleLink_In", makeNetIndex(0, number_bits_per_flit-1)); + createNet("IngressToMiddleLink_Out", makeNetIndex(0, number_bits_per_flit-1)); + portConnect(ingress_to_middle_link, "In", "IngressToMiddleLink_In"); + portConnect(ingress_to_middle_link, "Out", "IngressToMiddleLink_Out"); + + createNet("MiddleToEgressLink_In", makeNetIndex(0, number_bits_per_flit-1)); + createNet("MiddleToEgressLink_Out", makeNetIndex(0, number_bits_per_flit-1)); + portConnect(middle_to_egress_link, "In", "MiddleToEgressLink_In"); + portConnect(middle_to_egress_link, "Out", "MiddleToEgressLink_Out"); + + createNet("EgressToOutputLink_In", makeNetIndex(0, number_bits_per_flit-1)); + createNet("EgressToOutputLink_Out", makeNetIndex(0, number_bits_per_flit-1)); + portConnect(egress_to_output_link, "In", "EgressToOutputLink_In"); + portConnect(egress_to_output_link, "Out", "EgressToOutputLink_Out"); + + + portConnect(ingress_router, "CK", "CK"); + for(unsigned int i = 0; i < ingress_router_number_input_ports; ++i) + { + createNet("IngressRouter_In" + (String)i, makeNetIndex(0, number_bits_per_flit-1)); + for (unsigned int j = 0; j < number_bits_per_flit; ++j) + assignVirtualFanout("IngressRouter_In" + (String)i, makeNetIndex(j), "InputToIngressLink_Out", makeNetIndex(j)); + portConnect(ingress_router, "FlitIn" + (String)i, "IngressRouter_In" + (String)i); + } + for(unsigned int i = 0; i < ingress_router_number_output_ports; ++i) + { + // VFI + portConnect(ingress_router, "FlitOut" + (String)i, "IngressToMiddleLink_In"); + } + + portConnect(middle_router, "CK", "CK"); + for(unsigned int i = 0; i < middle_router_number_input_ports; ++i) + { + createNet("MiddleRouter_In" + (String)i, makeNetIndex(0, number_bits_per_flit-1)); + for (unsigned int j = 0; j < number_bits_per_flit; ++j) + assignVirtualFanout("MiddleRouter_In" + (String)i, makeNetIndex(j), "IngressToMiddleLink_Out", makeNetIndex(j)); + portConnect(middle_router, "FlitIn" + (String)i, "MiddleRouter_In" + (String)i); + } + for(unsigned int i = 0; i < middle_router_number_output_ports; ++i) + { + // VFI + portConnect(middle_router, "FlitOut" + (String)i, "MiddleToEgressLink_In"); + } + + portConnect(egress_router, "CK", "CK"); + for(unsigned int i = 0; i < egress_router_number_input_ports; ++i) + { + createNet("EgressRouter_In" + (String)i, makeNetIndex(0, number_bits_per_flit-1)); + for (unsigned int j = 0; j < number_bits_per_flit; ++j) + assignVirtualFanout("EgressRouter_In" + (String)i, makeNetIndex(j), "MiddleToEgressLink_Out", makeNetIndex(j)); + portConnect(egress_router, "FlitIn" + (String)i, "EgressRouter_In" + (String)i); + } + for(unsigned int i = 0; i < egress_router_number_output_ports; ++i) + { + // VFI + portConnect(egress_router, "FlitOut" + (String)i, "EgressToOutputLink_In"); + } + + // Create area, power, and event results + createElectricalResults(); + createElectricalEventResult("AvgUnicast"); + createElectricalEventResult("AvgBroadcast"); + + // Add all instances + addSubInstances(ingress_router, number_ingress_routers); + addElectricalSubResults(ingress_router, number_ingress_routers); + addSubInstances(middle_router, number_middle_routers); + addElectricalSubResults(middle_router, number_middle_routers); + addSubInstances(egress_router, number_egress_routers); + addElectricalSubResults(egress_router, number_egress_routers); + addSubInstances(input_to_ingress_link, number_input_to_ingress_links); + addElectricalSubResults(input_to_ingress_link, number_input_to_ingress_links); + addSubInstances(ingress_to_middle_link, number_ingress_to_middle_links); + addElectricalSubResults(ingress_to_middle_link, number_ingress_to_middle_links); + addSubInstances(middle_to_egress_link, number_middle_to_egress_links); + addElectricalSubResults(middle_to_egress_link, number_middle_to_egress_links); + addSubInstances(egress_to_output_link, number_egress_to_output_links); + addElectricalSubResults(egress_to_output_link, number_egress_to_output_links); + + // Update unicast event + Result* avg_unicast_event = getEventResult("AvgUnicast"); + avg_unicast_event->addSubResult(input_to_ingress_link->getEventResult("Send"), "InputToIngressLink", 1.0); + if(ingress_router->hasEventResult("WriteBuffer")) + { + avg_unicast_event->addSubResult(ingress_router->getEventResult("WriteBuffer"), "IngressRouter", 1.0); + } + if(ingress_router->hasEventResult("ReadBuffer")) + { + avg_unicast_event->addSubResult(ingress_router->getEventResult("ReadBuffer"), "IngressRouter", 1.0); + } + avg_unicast_event->addSubResult(ingress_router->getEventResult("TraverseCrossbar->Multicast1"), "IngressRouter", 1.0); + avg_unicast_event->addSubResult(ingress_to_middle_link->getEventResult("Send"), "IngressToMiddleLink", 1.0); + if(middle_router->hasEventResult("WriteBuffer")) + { + avg_unicast_event->addSubResult(middle_router->getEventResult("WriteBuffer"), "MiddleRouter", 1.0); + } + if(middle_router->hasEventResult("ReadBuffer")) + { + avg_unicast_event->addSubResult(middle_router->getEventResult("ReadBuffer"), "MiddleRouter", 1.0); + } + avg_unicast_event->addSubResult(middle_router->getEventResult("TraverseCrossbar->Multicast1"), "MiddleRouter", 1.0); + avg_unicast_event->addSubResult(middle_to_egress_link->getEventResult("Send"), "MiddleToEgressLink", 1.0); + if(egress_router->hasEventResult("WriteBuffer")) + { + avg_unicast_event->addSubResult(egress_router->getEventResult("WriteBuffer"), "EgressRouter", 1.0); + } + if(egress_router->hasEventResult("ReadBuffer")) + { + avg_unicast_event->addSubResult(egress_router->getEventResult("ReadBuffer"), "EgressRouter", 1.0); + } + avg_unicast_event->addSubResult(egress_router->getEventResult("TraverseCrossbar->Multicast1"), "EgressRouter", 1.0); + avg_unicast_event->addSubResult(egress_to_output_link->getEventResult("Send"), "EgressToOutputLink", 1.0); + + // Update broadcast event + Result* avg_broadcast_event = getEventResult("AvgBroadcast"); + avg_broadcast_event->addSubResult(input_to_ingress_link->getEventResult("Send"), "InputToIngressLink", 1.0); + if(ingress_router->hasEventResult("WriteBuffer")) + { + avg_broadcast_event->addSubResult(ingress_router->getEventResult("WriteBuffer"), "IngressRouter", 1.0); + } + if(ingress_router->hasEventResult("ReadBuffer")) + { + avg_broadcast_event->addSubResult(ingress_router->getEventResult("ReadBuffer"), "IngressRouter", 1.0); + } + avg_broadcast_event->addSubResult(ingress_router->getEventResult("TraverseCrossbar->Multicast1"), "IngressRouter", 1.0); + avg_broadcast_event->addSubResult(ingress_to_middle_link->getEventResult("Send"), "IngressToMiddleLink", 1.0); + if(middle_router->hasEventResult("WriteBuffer")) + { + avg_broadcast_event->addSubResult(middle_router->getEventResult("WriteBuffer"), "MiddleRouter", 1.0); + } + if(middle_router->hasEventResult("ReadBuffer")) + { + avg_broadcast_event->addSubResult(middle_router->getEventResult("ReadBuffer"), "MiddleRouter", 1.0); + } + avg_broadcast_event->addSubResult(middle_router->getEventResult("TraverseCrossbar->Multicast1"), "MiddleRouter", 1.0); + avg_broadcast_event->addSubResult(middle_to_egress_link->getEventResult("Send"), "MiddleToEgressLink", number_egress_routers); + if(egress_router->hasEventResult("WriteBuffer")) + { + avg_broadcast_event->addSubResult(egress_router->getEventResult("WriteBuffer"), "EgressRouter", number_egress_routers); + } + if(egress_router->hasEventResult("ReadBuffer")) + { + avg_broadcast_event->addSubResult(egress_router->getEventResult("ReadBuffer"), "EgressRouter", number_egress_routers); + } + avg_broadcast_event->addSubResult(egress_router->getEventResult("TraverseCrossbar->Multicast" + (String)number_egress_routers), "EgressRouter", 1.0); + avg_broadcast_event->addSubResult(egress_to_output_link->getEventResult("Send"), "EgressToOutputLink", number_output_sites); + return; + } + + void ElectricalClos::updateModel() + { + // Get properties + double input_site_pitch = getProperty("InputSitePitch").toDouble(); + double output_site_pitch = getProperty("OutputSitePitch").toDouble(); + double clock_freq = getParameter("Frequency"); + + ASSERT(input_site_pitch > 0, "[Error] " + getInstanceName() + + " -> Input site pitch must be > 0!"); + ASSERT(output_site_pitch > 0, "[Error] " + getInstanceName() + + " -> Output site pitch must be > 0!"); + ASSERT(clock_freq > 0, "[Error] " + getInstanceName() + + " -> Clock frequency must be > 0!"); + + unsigned int number_input_sites_per_ingress_router = getGenProperties()->get("NumberInputSitesPerIngressRouter"); + unsigned int number_ingress_routers = getParameter("NumberIngressRouters"); + unsigned int number_output_sites_per_egress_router = getGenProperties()->get("NumberOutputSitesPerEgressRouter"); + unsigned int number_egress_routers = getParameter("NumberEgressRouters"); + double delay = 1.0 / clock_freq; + + double input_to_ingress_link_length = input_site_pitch * (sqrt(number_input_sites_per_ingress_router) - 1.0); + double input_to_ingress_link_delay = delay * 0.8; + double ingress_to_middle_link_length = input_site_pitch * (sqrt(number_input_sites_per_ingress_router) * sqrt(number_ingress_routers)); + double ingress_to_middle_link_delay = delay * 0.8; + double middle_to_egress_link_length = output_site_pitch * (sqrt(number_output_sites_per_egress_router) * sqrt(number_egress_routers)); + double middle_to_egress_link_delay = delay * 0.8; + double egress_to_output_link_length = output_site_pitch * (sqrt(number_output_sites_per_egress_router) - 1.0); + double egress_to_output_link_delay = delay * 0.8; + double ingress_router_delay = delay; + double middle_router_delay = delay; + double egress_router_delay = delay; + + Model* input_to_ingress_link = getSubInstance("InputToIngressLink"); + input_to_ingress_link->setProperty("WireLength", input_to_ingress_link_length); + input_to_ingress_link->setProperty("Delay", input_to_ingress_link_delay); + input_to_ingress_link->setProperty("IsKeepParity", "TRUE"); + input_to_ingress_link->update(); + + Model* ingress_to_middle_link = getSubInstance("IngressToMiddleLink"); + ingress_to_middle_link->setProperty("WireLength", ingress_to_middle_link_length); + ingress_to_middle_link->setProperty("Delay", ingress_to_middle_link_delay); + ingress_to_middle_link->setProperty("IsKeepParity", "TRUE"); + ingress_to_middle_link->update(); + + Model* middle_to_egress_link = getSubInstance("MiddleToEgressLink"); + middle_to_egress_link->setProperty("WireLength", middle_to_egress_link_length); + middle_to_egress_link->setProperty("Delay", middle_to_egress_link_delay); + middle_to_egress_link->setProperty("IsKeepParity", "TRUE"); + middle_to_egress_link->update(); + + Model* egress_to_output_link = getSubInstance("EgressToOutputLink"); + egress_to_output_link->setProperty("WireLength", egress_to_output_link_length); + egress_to_output_link->setProperty("Delay", egress_to_output_link_delay); + egress_to_output_link->setProperty("IsKeepParity", "TRUE"); + egress_to_output_link->update(); + + ElectricalModel* ingress_router = (ElectricalModel*)getSubInstance("IngressRouter"); + ingress_router->update(); + + ElectricalTimingTree ingress_router_timing_tree("IngressRouter", ingress_router); + ingress_router_timing_tree.performTimingOpt(ingress_router->getNet("CK"), ingress_router_delay); + + ElectricalModel* middle_router = (ElectricalModel*)getSubInstance("MiddleRouter"); + middle_router->update(); + + ElectricalTimingTree middle_router_timing_tree("MiddleRouter", middle_router); + middle_router_timing_tree.performTimingOpt(middle_router->getNet("CK"), middle_router_delay); + + ElectricalModel* egress_router = (ElectricalModel*)getSubInstance("EgressRouter"); + egress_router->update(); + + ElectricalTimingTree egress_router_timing_tree("EgressRouter", egress_router); + egress_router_timing_tree.performTimingOpt(egress_router->getNet("CK"), egress_router_delay); + + return; + } + + void ElectricalClos::propagateTransitionInfo() + { + // Get properties + unsigned int ingress_router_number_input_ports = getGenProperties()->get("IngressRouter->NumberInputPorts"); + unsigned int middle_router_number_input_ports = getGenProperties()->get("MiddleRouter->NumberInputPorts"); + unsigned int egress_router_number_input_ports = getGenProperties()->get("EgressRouter->NumberInputPorts"); + + ElectricalModel* input_to_ingress_link = (ElectricalModel*)getSubInstance("InputToIngressLink"); + assignPortTransitionInfo(input_to_ingress_link, "In", TransitionInfo(0.25, 0.25, 0.25)); + input_to_ingress_link->use(); + + ElectricalModel* ingress_to_middle_link = (ElectricalModel*)getSubInstance("IngressToMiddleLink"); + assignPortTransitionInfo(ingress_to_middle_link, "In", TransitionInfo(0.25, 0.25, 0.25)); + ingress_to_middle_link->use(); + + ElectricalModel* middle_to_egress_link = (ElectricalModel*)getSubInstance("MiddleToEgressLink"); + assignPortTransitionInfo(middle_to_egress_link, "In", TransitionInfo(0.25, 0.25, 0.25)); + middle_to_egress_link->use(); + + ElectricalModel* egress_to_output_link = (ElectricalModel*)getSubInstance("EgressToOutputLink"); + assignPortTransitionInfo(egress_to_output_link, "In", TransitionInfo(0.25, 0.25, 0.25)); + egress_to_output_link->use(); + + ElectricalModel* ingress_router = (ElectricalModel*)getSubInstance("IngressRouter"); + for(unsigned int i = 0; i < ingress_router_number_input_ports; ++i) + { + assignPortTransitionInfo(ingress_router, "FlitIn" + (String)i, TransitionInfo(0.25, 0.25, 0.25)); + } + assignPortTransitionInfo(ingress_router, "CK", TransitionInfo(0.0, 1.0, 0.0)); + ingress_router->getGenProperties()->set("UseModelEvent", ""); + ingress_router->use(); + + ElectricalModel* middle_router = (ElectricalModel*)getSubInstance("MiddleRouter"); + for(unsigned int i = 0; i < middle_router_number_input_ports; ++i) + { + assignPortTransitionInfo(middle_router, "FlitIn" + (String)i, TransitionInfo(0.25, 0.25, 0.25)); + } + assignPortTransitionInfo(middle_router, "CK", TransitionInfo(0.0, 1.0, 0.0)); + middle_router->getGenProperties()->set("UseModelEvent", ""); + middle_router->use(); + + ElectricalModel* egress_router = (ElectricalModel*)getSubInstance("EgressRouter"); + for(unsigned int i = 0; i < egress_router_number_input_ports; ++i) + { + assignPortTransitionInfo(egress_router, "FlitIn" + (String)i, TransitionInfo(0.25, 0.25, 0.25)); + } + assignPortTransitionInfo(egress_router, "CK", TransitionInfo(0.0, 1.0, 0.0)); + egress_router->getGenProperties()->set("UseModelEvent", ""); + egress_router->use(); + + return; + } +} // namespace DSENT + diff --git a/ext/dsent/model/network/ElectricalClos.h b/ext/dsent/model/network/ElectricalClos.h new file mode 100644 index 000000000..c6a1f8063 --- /dev/null +++ b/ext/dsent/model/network/ElectricalClos.h @@ -0,0 +1,37 @@ +#ifndef __DSENT_MODEL_NETWORK_ELECTRICAL_CLOS_H__ +#define __DSENT_MODEL_NETWORK_ELECTRICAL_CLOS_H__ + +#include "util/CommonType.h" +#include "model/ElectricalModel.h" + +namespace DSENT +{ + /** + * \brief An electrical 3-stage clos network + */ + class ElectricalClos : public ElectricalModel + { + public: + ElectricalClos(const String& instance_name_, const TechModel* tech_model_); + virtual ~ElectricalClos(); + + public: + // Set a list of properties' name needed to construct model + void initParameters(); + // Set a list of properties' name needed to construct model + void initProperties(); + + // Clone and return a new instance + virtual ElectricalClos* clone() const; + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void propagateTransitionInfo(); + + }; +} // namespace DSENT + +#endif // __DSENT_MODEL_NETWORK_ELECTRICAL_CLOS_H__ + diff --git a/ext/dsent/model/network/ElectricalMesh.cc b/ext/dsent/model/network/ElectricalMesh.cc new file mode 100644 index 000000000..5ad544eb5 --- /dev/null +++ b/ext/dsent/model/network/ElectricalMesh.cc @@ -0,0 +1,296 @@ +#include "model/network/ElectricalMesh.h" + +#include <cmath> + +#include "model/PortInfo.h" +#include "model/EventInfo.h" +#include "model/TransitionInfo.h" +#include "model/ModelGen.h" +#include "model/std_cells/StdCellLib.h" +#include "model/timing_graph/ElectricalTimingTree.h" +#include "model/timing_graph/ElectricalNet.h" + +namespace DSENT +{ + using std::sqrt; + + ElectricalMesh::ElectricalMesh(const String& instance_name_, const TechModel* tech_model_) + : ElectricalModel(instance_name_, tech_model_) + { + initParameters(); + initProperties(); + } + + ElectricalMesh::~ElectricalMesh() + {} + + void ElectricalMesh::initParameters() + { + // Clock Frequency + addParameterName("Frequency"); + // Physical Parameters + addParameterName("NumberSites"); + addParameterName("NumberBitsPerFlit"); + // Concentration factor + addParameterName("NumberSitesPerRouter"); + // Router parameters + addParameterName("Router->NumberVirtualNetworks"); + addParameterName("Router->NumberVirtualChannelsPerVirtualNetwork"); + addParameterName("Router->NumberBuffersPerVirtualChannel"); + addParameterName("Router->InputPort->BufferModel"); + addParameterName("Router->CrossbarModel"); + addParameterName("Router->SwitchAllocator->ArbiterModel"); + addParameterName("Router->ClockTreeModel"); + addParameterName("Router->ClockTree->NumberLevels"); + addParameterName("Router->ClockTree->WireLayer"); + addParameterName("Router->ClockTree->WireWidthMultiplier"); + addParameterName("Router->ClockTree->WireSpacingMultiplier", 3.0); + // Link parameters + addParameterName("Link->WireLayer"); + addParameterName("Link->WireWidthMultiplier"); + addParameterName("Link->WireSpacingMultiplier"); + return; + } + + void ElectricalMesh::initProperties() + { + addPropertyName("SitePitch"); + return; + } + + ElectricalMesh* ElectricalMesh::clone() const + { + // TODO + return NULL; + } + + void ElectricalMesh::constructModel() + { + // Get input paramters + unsigned int number_sites = getParameter("NumberSites").toUInt(); + unsigned int number_bits_per_flit = getParameter("NumberBitsPerFlit").toUInt(); + unsigned int number_sites_per_router = getParameter("NumberSitesPerRouter").toUInt(); + + ASSERT(number_sites > 0, "[Error] " + getInstanceName() + + " -> Number of sites must be > 0!"); + ASSERT(number_bits_per_flit > 0, "[Error] " + getInstanceName() + + " -> Number of bits per flit must be > 0!"); + ASSERT(number_sites_per_router > 0, "[Error] " + getInstanceName() + + " -> Number of sites per router must be > 0!"); + + // Get input parameters that will be forwarded to the sub instances + const String& router_number_vns = getParameter("Router->NumberVirtualNetworks"); + const String& router_number_vcs_per_vn = getParameter("Router->NumberVirtualChannelsPerVirtualNetwork"); + const String& router_number_bufs_per_vc = getParameter("Router->NumberBuffersPerVirtualChannel"); + const String& link_wire_layer = getParameter("Link->WireLayer"); + const String& link_wire_width_multiplier = getParameter("Link->WireWidthMultiplier"); + const String& link_wire_spacing_multiplier = getParameter("Link->WireSpacingMultiplier"); + + // Calculate properties from input parameters + unsigned int number_routers = number_sites / number_sites_per_router; + unsigned int number_router_to_router_links = 4 * number_routers; + unsigned int number_router_to_site_links = 2 * number_sites; + unsigned int router_number_input_ports = 4 + number_sites_per_router; + unsigned int router_number_output_ports = 4 + number_sites_per_router; + + getGenProperties()->set("NumberRouters", number_routers); + getGenProperties()->set("NumberRouterToRouterLinks", number_router_to_router_links); + getGenProperties()->set("NumberRouterToSiteLinks", number_router_to_site_links); + getGenProperties()->set("Router->NumberInputPorts", router_number_input_ports); + getGenProperties()->set("Router->NumberOutputPorts", router_number_output_ports); + + // Create ports + createInputPort("CK"); + + // Init mesh routers + ElectricalModel* router = (ElectricalModel*)ModelGen::createModel("Router", "MeshRouter", getTechModel()); + router->setParameter("NumberInputPorts", router_number_input_ports); + router->setParameter("NumberOutputPorts", router_number_output_ports); + router->setParameter("NumberVirtualNetworks", router_number_vns); + router->setParameter("NumberVirtualChannelsPerVirtualNetwork", router_number_vcs_per_vn); + router->setParameter("NumberBuffersPerVirtualChannel", router_number_bufs_per_vc); + router->setParameter("NumberBitsPerFlit", number_bits_per_flit); + router->setParameter("InputPort->BufferModel", getParameter("Router->InputPort->BufferModel")); + router->setParameter("CrossbarModel", getParameter("Router->CrossbarModel")); + router->setParameter("SwitchAllocator->ArbiterModel", getParameter("Router->SwitchAllocator->ArbiterModel")); + router->setParameter("ClockTreeModel", getParameter("Router->ClockTreeModel")); + router->setParameter("ClockTree->NumberLevels", getParameter("Router->ClockTree->NumberLevels")); + router->setParameter("ClockTree->WireLayer", getParameter("Router->ClockTree->WireLayer")); + router->setParameter("ClockTree->WireWidthMultiplier", getParameter("Router->ClockTree->WireWidthMultiplier")); + router->setParameter("ClockTree->WireSpacingMultiplier", getParameter("Router->ClockTree->WireSpacingMultiplier")); + router->construct(); + + // Init router to router links + ElectricalModel* rr_link = (ElectricalModel*)ModelGen::createModel("RepeatedLink", "RouterToRouterLink", getTechModel()); + rr_link->setParameter("NumberBits", number_bits_per_flit); + rr_link->setParameter("WireLayer", link_wire_layer); + rr_link->setParameter("WireWidthMultiplier", link_wire_width_multiplier); + rr_link->setParameter("WireSpacingMultiplier", link_wire_spacing_multiplier); + rr_link->construct(); + + // Init router to site links + ElectricalModel* rs_link = (ElectricalModel*)ModelGen::createModel("RepeatedLink", "RouterToSiteLink", getTechModel()); + rs_link->setParameter("NumberBits", number_bits_per_flit); + rs_link->setParameter("WireLayer", link_wire_layer); + rs_link->setParameter("WireWidthMultiplier", link_wire_width_multiplier); + rs_link->setParameter("WireSpacingMultiplier", link_wire_spacing_multiplier); + rs_link->construct(); + + // Connect ports + createNet("RR_Link_Out", makeNetIndex(0, number_bits_per_flit-1)); + createNet("RR_Link_In", makeNetIndex(0, number_bits_per_flit-1)); + portConnect(rr_link, "In", "RR_Link_In"); + portConnect(rr_link, "Out", "RR_Link_Out"); + + createNet("RS_Link_Out", makeNetIndex(0, number_bits_per_flit-1)); + createNet("RS_Link_In", makeNetIndex(0, number_bits_per_flit-1)); + portConnect(rs_link, "In", "RS_Link_In"); + portConnect(rs_link, "Out", "RS_Link_Out"); + + portConnect(router, "CK", "CK"); + for(unsigned int i = 0; i < router_number_input_ports; ++i) + { + createNet("Router_In" + (String)i, makeNetIndex(0, number_bits_per_flit-1)); + portConnect(router, "FlitIn" + (String)i, "Router_In" + (String)i); + } + for(unsigned int i = 0; i < router_number_output_ports; ++i) + { + createNet("Router_Out" + (String)i, makeNetIndex(0, number_bits_per_flit-1)); + portConnect(router, "FlitOut" + (String)i, "Router_Out" + (String)i); + } + for(unsigned int i = 0; i < number_bits_per_flit; ++i) + { + for(unsigned int j = 0; j < 4; ++j) + { + assignVirtualFanout("Router_In" + (String)j, makeNetIndex(i), "RR_Link_Out", makeNetIndex(i)); + assignVirtualFanin("RR_Link_In", makeNetIndex(i), "Router_Out" + (String)j, makeNetIndex(i)); + } + for(unsigned int j = 4; j < router_number_input_ports; ++j) + { + assignVirtualFanout("Router_In" + (String)j, makeNetIndex(i), "RS_Link_Out", makeNetIndex(i)); + assignVirtualFanin("RS_Link_In", makeNetIndex(i), "Router_Out" + (String)j, makeNetIndex(i)); + } + } + + // Create area, power and event results + createElectricalResults(); + createElectricalEventResult("AvgUnicast"); + createElectricalEventResult("AvgBroadcast"); + + // Add all instances + addSubInstances(router, number_routers); + addElectricalSubResults(router, number_routers); + addSubInstances(rr_link, number_router_to_router_links); + addElectricalSubResults(rr_link, number_router_to_router_links); + addSubInstances(rs_link, number_router_to_site_links); + addElectricalSubResults(rs_link, number_router_to_site_links); + + double number_routers_per_side = sqrt(number_routers); + + // Update unicast event + double avg_number_unicast_hop = 2.0 * number_routers_per_side / 3.0; + double avg_number_unicast_rr_links_traveled = avg_number_unicast_hop; + double avg_number_unicast_rs_links_traveled = 2.0; + double avg_number_unicast_router_traveled = avg_number_unicast_hop + 1.0; + Result* avg_unicast_flit = getEventResult("AvgUnicast"); + avg_unicast_flit->addSubResult(rr_link->getEventResult("Send"), "RouterToRouterLink", avg_number_unicast_rr_links_traveled); + avg_unicast_flit->addSubResult(rs_link->getEventResult("Send"), "RouterToSiteLink", avg_number_unicast_rs_links_traveled); + if(router->hasEventResult("WriteBuffer")) + { + avg_unicast_flit->addSubResult(router->getEventResult("WriteBuffer"), "MeshRouter", avg_number_unicast_router_traveled); + } + if(router->hasEventResult("ReadBuffer")) + { + avg_unicast_flit->addSubResult(router->getEventResult("ReadBuffer"), "MeshRouter", avg_number_unicast_router_traveled); + } + avg_unicast_flit->addSubResult(router->getEventResult("TraverseCrossbar->Multicast1"), "MeshRouter", avg_number_unicast_router_traveled); + + // Update broadcast event + double avg_number_broadcast_rr_links_traveled = (number_routers_per_side - 1.0) * number_routers_per_side + number_routers_per_side - 1.0; + double avg_number_broadcast_rs_links_traveled = number_sites; + double avg_number_broadcast_router_crossbar_traveled = number_routers * (number_sites_per_router + 1.0) - 2.0; + Result* avg_broadcast_flit = getEventResult("AvgBroadcast"); + avg_broadcast_flit->addSubResult(rr_link->getEventResult("Send"), "RouterToRouterLink", avg_number_broadcast_rr_links_traveled); + avg_broadcast_flit->addSubResult(rs_link->getEventResult("Send"), "RouterToSiteLink", avg_number_broadcast_rs_links_traveled); + if(router->hasEventResult("WriteBuffer")) + { + avg_broadcast_flit->addSubResult(router->getEventResult("WriteBuffer"), "MeshRouter", number_routers); + } + if(router->hasEventResult("ReadBuffer")) + { + avg_broadcast_flit->addSubResult(router->getEventResult("ReadBuffer"), "MeshRouter", number_routers); + } + avg_broadcast_flit->addSubResult(router->getEventResult("TraverseCrossbar->Multicast1"), "MeshRouter", avg_number_broadcast_router_crossbar_traveled); + + return; + } + + void ElectricalMesh::updateModel() + { + // Get properties + double site_pitch = getProperty("SitePitch").toDouble(); + double clock_freq = getParameter("Frequency"); + + ASSERT(site_pitch > 0, "[Error] " + getInstanceName() + + " -> Site pitch must be > 0!"); + ASSERT(clock_freq > 0, "[Error] " + getInstanceName() + + " -> Clock frequency must be > 0!"); + + unsigned int number_sites_per_router = getParameter("NumberSitesPerRouter"); + // Get margin on link delays, since there are registers before and after the link + double delay_ck_to_q = getTechModel()->getStdCellLib()->getStdCellCache()->get("DFFQ_X1->Delay->CK_to_Q"); + double delay_setup = getTechModel()->getStdCellLib()->getStdCellCache()->get("DFFQ_X1->Delay->CK_to_Q"); + double link_delay_margin = (delay_ck_to_q + delay_setup) * 1.5; + + double rr_link_length = site_pitch * sqrt(number_sites_per_router); + double rr_link_delay = std::max(1e-99, 1.0 / clock_freq - link_delay_margin); + double rs_link_length = site_pitch * (sqrt(number_sites_per_router) - 1.0); + double rs_link_delay = std::max(1e-99, 1.0 / clock_freq - link_delay_margin ); + double router_delay = 1.0 / clock_freq; + + Model* rr_link = getSubInstance("RouterToRouterLink"); + rr_link->setProperty("WireLength", rr_link_length); + rr_link->setProperty("Delay", rr_link_delay); + rr_link->setProperty("IsKeepParity", "TRUE"); + rr_link->update(); + + Model* rs_link = getSubInstance("RouterToSiteLink"); + rs_link->setProperty("WireLength", rs_link_length); + rs_link->setProperty("Delay", rs_link_delay); + rs_link->setProperty("IsKeepParity", "TRUE"); + rs_link->update(); + + ElectricalModel* router = (ElectricalModel*)getSubInstance("MeshRouter"); + router->update(); + + ElectricalTimingTree router_timing_tree("MeshRouter", router); + router_timing_tree.performTimingOpt(router->getNet("CK"), router_delay); + return; + } + + void ElectricalMesh::propagateTransitionInfo() + { + // Get parameters + unsigned int router_number_input_ports = getGenProperties()->get("Router->NumberInputPorts"); + + ElectricalModel* rr_link = (ElectricalModel*)getSubInstance("RouterToRouterLink"); + assignPortTransitionInfo(rr_link, "In", TransitionInfo(0.25, 0.25, 0.25)); + rr_link->use(); + + ElectricalModel* rs_link = (ElectricalModel*)getSubInstance("RouterToSiteLink"); + assignPortTransitionInfo(rs_link, "In", TransitionInfo(0.25, 0.25, 0.25)); + rs_link->use(); + + ElectricalModel* router = (ElectricalModel*)getSubInstance("MeshRouter"); + for(unsigned int i = 0; i < router_number_input_ports; ++i) + { + assignPortTransitionInfo(router, "FlitIn" + (String)i, TransitionInfo(0.25, 0.25, 0.25)); + } + assignPortTransitionInfo(router, "CK", TransitionInfo(0.0, 1.0, 0.0)); + router->getGenProperties()->set("UseModelEvent", ""); + router->use(); + + return; + } +} // namespace DSENT + diff --git a/ext/dsent/model/network/ElectricalMesh.h b/ext/dsent/model/network/ElectricalMesh.h new file mode 100644 index 000000000..de89a8f80 --- /dev/null +++ b/ext/dsent/model/network/ElectricalMesh.h @@ -0,0 +1,37 @@ +#ifndef __DSENT_MODEL_NETWORK_ELECTRICAL_MESH_H__ +#define __DSENT_MODEL_NETWORK_ELECTRICAL_MESH_H__ + +#include "util/CommonType.h" +#include "model/ElectricalModel.h" + +namespace DSENT +{ + /** + * \brief An electrical mesh network + */ + class ElectricalMesh : public ElectricalModel + { + public: + ElectricalMesh(const String& instance_name_, const TechModel* tech_model_); + virtual ~ElectricalMesh(); + + public: + // Set a list of properties' name needed to construct model + void initParameters(); + // Set a list of properties' name needed to construct model + void initProperties(); + + // Clone and return a new instance + virtual ElectricalMesh* clone() const; + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void propagateTransitionInfo(); + + }; // class ElectricalMesh +} // namespace DSENT + +#endif // __DSENT_MODEL_NETWORK_ELECTRICAL_MESH_H__ + diff --git a/ext/dsent/model/network/PhotonicClos.cc b/ext/dsent/model/network/PhotonicClos.cc new file mode 100644 index 000000000..1b0868ebc --- /dev/null +++ b/ext/dsent/model/network/PhotonicClos.cc @@ -0,0 +1,512 @@ +#include "model/network/PhotonicClos.h" + +#include <cmath> + +#include "model/ModelGen.h" +#include "model/timing_graph/ElectricalTimingTree.h" +#include "model/timing_graph/ElectricalNet.h" + +namespace DSENT +{ + using std::sqrt; + + PhotonicClos::PhotonicClos(const String& instance_name_, const TechModel* tech_model_) + : ElectricalModel(instance_name_, tech_model_) + { + initParameters(); + initProperties(); + } + + PhotonicClos::~PhotonicClos() + {} + + void PhotonicClos::initParameters() + { + // Clock Frequency + addParameterName("Frequency"); + // Physical Parameters + addParameterName("NumberInputSites"); + addParameterName("NumberOutputSites"); + addParameterName("NumberBitsPerFlit"); + // Number of each type of routers + addParameterName("NumberIngressRouters"); + addParameterName("NumberMiddleRouters"); + addParameterName("NumberEgressRouters"); + // Optical link parameters + addParameterName("SWSR->LinkDataRate"); + addParameterName("SWSR->LaserType"); + addParameterName("SWSR->RingTuningMethod"); + // Router parameters + addParameterName("Router->NumberVirtualNetworks"); + addParameterName("Router->NumberVirtualChannelsPerVirtualNetwork"); + addParameterName("Router->NumberBuffersPerVirtualChannel"); + addParameterName("Router->InputPort->BufferModel"); + addParameterName("Router->CrossbarModel"); + addParameterName("Router->SwitchAllocator->ArbiterModel"); + addParameterName("Router->ClockTreeModel"); + addParameterName("Router->ClockTree->NumberLevels"); + addParameterName("Router->ClockTree->WireLayer"); + addParameterName("Router->ClockTree->WireWidthMultiplier"); + addParameterName("Router->ClockTree->WireSpacingMultiplier", 3.0); + // Link parameters + addParameterName("Link->WireLayer"); + addParameterName("Link->WireWidthMultiplier"); + addParameterName("Link->WireSpacingMultiplier"); + return; + } + + void PhotonicClos::initProperties() + { + addPropertyName("InputSitePitch"); + addPropertyName("OutputSitePitch"); + addPropertyName("SWSR->OptUtil", 1.0); + return; + } + + PhotonicClos* PhotonicClos::clone() const + { + // TODO + return NULL; + } + + void PhotonicClos::constructModel() + { + // Get input parameters + double clock_freq = getParameter("Frequency"); + unsigned int number_input_sites = getParameter("NumberInputSites").toUInt(); + unsigned int number_output_sites = getParameter("NumberOutputSites").toUInt(); + unsigned int number_bits_per_flit = getParameter("NumberBitsPerFlit").toUInt(); + unsigned int number_ingress_routers = getParameter("NumberIngressRouters").toUInt(); + unsigned int number_middle_routers = getParameter("NumberMiddleRouters").toUInt(); + unsigned int number_egress_routers = getParameter("NumberEgressRouters").toUInt(); + + ASSERT(clock_freq > 0, "[Error] " + getInstanceName() + + " -> Clock frequency must be > 0!"); + ASSERT(number_input_sites > 0, "[Error] " + getInstanceName() + + " -> Number of input sites must be > 0!"); + ASSERT(number_output_sites > 0, "[Error] " + getInstanceName() + + " -> Number of output sites must be > 0!"); + ASSERT(number_bits_per_flit > 0, "[Error] " + getInstanceName() + + " -> Number of bits per flit must be > 0!"); + ASSERT(number_ingress_routers > 0, "[Error] " + getInstanceName() + + " -> Number of ingress routers must be > 0!"); + ASSERT(number_middle_routers > 0, "[Error] " + getInstanceName() + + " -> Number of middle routers must be > 0!"); + ASSERT(number_egress_routers > 0, "[Error] " + getInstanceName() + + " -> Number of egress routers must be > 0!"); + + // Get input parameters that will be forwarded to the sub instances + const String& swsr_link_data_rate = getParameter("SWSR->LinkDataRate"); + const String& swsr_laser_type = getParameter("SWSR->LaserType"); + const String& swsr_ring_tuning_method = getParameter("SWSR->RingTuningMethod"); + const String& router_number_vns = getParameter("Router->NumberVirtualNetworks"); + const String& router_number_vcs_per_vn = getParameter("Router->NumberVirtualChannelsPerVirtualNetwork"); + const String& router_number_bufs_per_vc = getParameter("Router->NumberBuffersPerVirtualChannel"); + const String& router_buffer_model = getParameter("Router->InputPort->BufferModel"); + const String& router_crossbar_model = getParameter("Router->CrossbarModel"); + const String& link_wire_layer = getParameter("Link->WireLayer"); + const String& link_wire_width_multiplier = getParameter("Link->WireWidthMultiplier"); + const String& link_wire_spacing_multiplier = getParameter("Link->WireSpacingMultiplier"); + + // Calculate properties from input parameters + unsigned int ingress_router_number_input_ports = number_input_sites / number_ingress_routers; + unsigned int ingress_router_number_output_ports = number_middle_routers; + unsigned int middle_router_number_input_ports = number_ingress_routers; + unsigned int middle_router_number_output_ports = number_egress_routers; + unsigned int egress_router_number_input_ports = number_middle_routers; + unsigned int egress_router_number_output_ports = number_output_sites / number_egress_routers; + unsigned int number_input_to_ingress_links = number_input_sites; + unsigned int number_ingress_to_middle_links = number_ingress_routers * number_middle_routers; + unsigned int number_middle_to_egress_links = number_middle_routers * number_egress_routers; + unsigned int number_egress_to_output_links = number_output_sites; + + getGenProperties()->set("NumberInputSitesPerIngressRouter", ingress_router_number_input_ports); + getGenProperties()->set("NumberOutputSitesPerEgressRouter", egress_router_number_output_ports); + getGenProperties()->set("IngressRouter->NumberInputPorts", ingress_router_number_input_ports); + getGenProperties()->set("IngressRouter->NumberOutputPorts", ingress_router_number_output_ports); + getGenProperties()->set("MiddleRouter->NumberInputPorts", middle_router_number_input_ports); + getGenProperties()->set("MiddleRouter->NumberOutputPorts", middle_router_number_output_ports); + getGenProperties()->set("EgressRouter->NumberInputPorts", egress_router_number_input_ports); + getGenProperties()->set("EgressRouter->NumberOutputPorts", egress_router_number_output_ports); + + // Create ports + createInputPort("CK"); + + // Init ingress router + ElectricalModel* ingress_router = (ElectricalModel*)ModelGen::createModel("Router", "IngressRouter", getTechModel()); + ingress_router->setParameter("NumberInputPorts", ingress_router_number_input_ports); + ingress_router->setParameter("NumberOutputPorts", ingress_router_number_output_ports); + ingress_router->setParameter("NumberVirtualNetworks", router_number_vns); + ingress_router->setParameter("NumberVirtualChannelsPerVirtualNetwork", router_number_vcs_per_vn); + ingress_router->setParameter("NumberBuffersPerVirtualChannel", router_number_bufs_per_vc); + ingress_router->setParameter("NumberBitsPerFlit", number_bits_per_flit); + ingress_router->setParameter("InputPort->BufferModel", router_buffer_model); + ingress_router->setParameter("CrossbarModel", router_crossbar_model); + ingress_router->setParameter("SwitchAllocator->ArbiterModel", getParameter("Router->SwitchAllocator->ArbiterModel")); + ingress_router->setParameter("ClockTreeModel", getParameter("Router->ClockTreeModel")); + ingress_router->setParameter("ClockTree->NumberLevels", getParameter("Router->ClockTree->NumberLevels")); + ingress_router->setParameter("ClockTree->WireLayer", getParameter("Router->ClockTree->WireLayer")); + ingress_router->setParameter("ClockTree->WireWidthMultiplier", getParameter("Router->ClockTree->WireWidthMultiplier")); + ingress_router->setParameter("ClockTree->WireSpacingMultiplier", getParameter("Router->ClockTree->WireSpacingMultiplier")); + ingress_router->construct(); + // Init middle routers + ElectricalModel* middle_router = (ElectricalModel*)ModelGen::createModel("Router", "MiddleRouter", getTechModel()); + middle_router->setParameter("NumberInputPorts", middle_router_number_input_ports); + middle_router->setParameter("NumberOutputPorts", middle_router_number_output_ports); + middle_router->setParameter("NumberVirtualNetworks", router_number_vns); + middle_router->setParameter("NumberVirtualChannelsPerVirtualNetwork", router_number_vcs_per_vn); + middle_router->setParameter("NumberBuffersPerVirtualChannel", router_number_bufs_per_vc); + middle_router->setParameter("NumberBitsPerFlit", number_bits_per_flit); + middle_router->setParameter("InputPort->BufferModel", router_buffer_model); + middle_router->setParameter("CrossbarModel", router_crossbar_model); + middle_router->setParameter("SwitchAllocator->ArbiterModel", getParameter("Router->SwitchAllocator->ArbiterModel")); + middle_router->setParameter("ClockTreeModel", getParameter("Router->ClockTreeModel")); + middle_router->setParameter("ClockTree->NumberLevels", getParameter("Router->ClockTree->NumberLevels")); + middle_router->setParameter("ClockTree->WireLayer", getParameter("Router->ClockTree->WireLayer")); + middle_router->setParameter("ClockTree->WireWidthMultiplier", getParameter("Router->ClockTree->WireWidthMultiplier")); + middle_router->setParameter("ClockTree->WireSpacingMultiplier", getParameter("Router->ClockTree->WireSpacingMultiplier")); + middle_router->construct(); + // Init egress routers + ElectricalModel* egress_router = (ElectricalModel*)ModelGen::createModel("Router", "EgressRouter", getTechModel()); + egress_router->setParameter("NumberInputPorts", egress_router_number_input_ports); + egress_router->setParameter("NumberOutputPorts", egress_router_number_output_ports); + egress_router->setParameter("NumberVirtualNetworks", router_number_vns); + egress_router->setParameter("NumberVirtualChannelsPerVirtualNetwork", router_number_vcs_per_vn); + egress_router->setParameter("NumberBuffersPerVirtualChannel", router_number_bufs_per_vc); + egress_router->setParameter("NumberBitsPerFlit", number_bits_per_flit); + egress_router->setParameter("InputPort->BufferModel", router_buffer_model); + egress_router->setParameter("CrossbarModel", router_crossbar_model); + egress_router->setParameter("SwitchAllocator->ArbiterModel", getParameter("Router->SwitchAllocator->ArbiterModel")); + egress_router->setParameter("ClockTreeModel", getParameter("Router->ClockTreeModel")); + egress_router->setParameter("ClockTree->NumberLevels", getParameter("Router->ClockTree->NumberLevels")); + egress_router->setParameter("ClockTree->WireLayer", getParameter("Router->ClockTree->WireLayer")); + egress_router->setParameter("ClockTree->WireWidthMultiplier", getParameter("Router->ClockTree->WireWidthMultiplier")); + egress_router->setParameter("ClockTree->WireSpacingMultiplier", getParameter("Router->ClockTree->WireSpacingMultiplier")); + egress_router->construct(); + // Init input to ingress link + ElectricalModel* input_to_ingress_link = (ElectricalModel*)ModelGen::createModel("RepeatedLink", "InputToIngressLink", getTechModel()); + input_to_ingress_link->setParameter("NumberBits", number_bits_per_flit); + input_to_ingress_link->setParameter("WireLayer", link_wire_layer); + input_to_ingress_link->setParameter("WireWidthMultiplier", link_wire_width_multiplier); + input_to_ingress_link->setParameter("WireSpacingMultiplier", link_wire_spacing_multiplier); + input_to_ingress_link->construct(); + // Init ingress to middle link + ElectricalModel* ingress_to_middle_link = (ElectricalModel*)ModelGen::createModel("SWSRLink", "IngressToMiddleLink", getTechModel()); + ingress_to_middle_link->setParameter("NumberBits", number_bits_per_flit); + ingress_to_middle_link->setParameter("CoreDataRate", clock_freq); + ingress_to_middle_link->setParameter("LinkDataRate", swsr_link_data_rate); + ingress_to_middle_link->setParameter("LaserType", swsr_laser_type); + ingress_to_middle_link->setParameter("RingTuningMethod", swsr_ring_tuning_method); + ingress_to_middle_link->construct(); + // Init middle to egress link + ElectricalModel* middle_to_egress_link = (ElectricalModel*)ModelGen::createModel("SWSRLink", "MiddleToEgressLink", getTechModel()); + middle_to_egress_link->setParameter("NumberBits", number_bits_per_flit); + middle_to_egress_link->setParameter("CoreDataRate", clock_freq); + middle_to_egress_link->setParameter("LinkDataRate", swsr_link_data_rate); + middle_to_egress_link->setParameter("LaserType", swsr_laser_type); + middle_to_egress_link->setParameter("RingTuningMethod", swsr_ring_tuning_method); + middle_to_egress_link->construct(); + // Init egress to output link + ElectricalModel* egress_to_output_link = (ElectricalModel*)ModelGen::createModel("RepeatedLink", "EgressToOutputLink", getTechModel()); + egress_to_output_link->setParameter("NumberBits", number_bits_per_flit); + egress_to_output_link->setParameter("WireLayer", link_wire_layer); + egress_to_output_link->setParameter("WireWidthMultiplier", link_wire_width_multiplier); + egress_to_output_link->setParameter("WireSpacingMultiplier", link_wire_spacing_multiplier); + egress_to_output_link->construct(); + + // Connect ports + createNet("InputToIngressLink_Out", makeNetIndex(0, number_bits_per_flit - 1)); + createNet("InputToIngressLink_In", makeNetIndex(0, number_bits_per_flit - 1)); + portConnect(input_to_ingress_link, "In", "InputToIngressLink_In"); + portConnect(input_to_ingress_link, "Out", "InputToIngressLink_Out"); + + createNet("IngressToMiddleLink_In", makeNetIndex(0, number_bits_per_flit - 1)); + createNet("IngressToMiddleLink_Out", makeNetIndex(0, number_bits_per_flit - 1)); + portConnect(ingress_to_middle_link, "In", "IngressToMiddleLink_In"); + portConnect(ingress_to_middle_link, "Out", "IngressToMiddleLink_Out"); + + createNet("MiddleToEgressLink_In", makeNetIndex(0, number_bits_per_flit - 1)); + createNet("MiddleToEgressLink_Out", makeNetIndex(0, number_bits_per_flit - 1)); + portConnect(middle_to_egress_link, "In", "MiddleToEgressLink_In"); + portConnect(middle_to_egress_link, "Out", "MiddleToEgressLink_Out"); + + createNet("EgressToOutputLink_In", makeNetIndex(0, number_bits_per_flit - 1)); + createNet("EgressToOutputLink_Out", makeNetIndex(0, number_bits_per_flit - 1)); + portConnect(egress_to_output_link, "In", "EgressToOutputLink_In"); + portConnect(egress_to_output_link, "Out", "EgressToOutputLink_Out"); + + portConnect(ingress_router, "CK", "CK"); + for(unsigned int i = 0; i < ingress_router_number_input_ports; ++i) + { + createNet("IngressRouter_In" + (String)i, makeNetIndex(0, number_bits_per_flit-1)); + for (unsigned int j = 0; j < number_bits_per_flit; ++j) + assignVirtualFanout("IngressRouter_In" + (String)i, makeNetIndex(j), "InputToIngressLink_Out", makeNetIndex(j)); + portConnect(ingress_router, "FlitIn" + (String)i, "IngressRouter_In" + (String)i); + } + for(unsigned int i = 0; i < ingress_router_number_output_ports; ++i) + { + // VFI + portConnect(ingress_router, "FlitOut" + (String)i, "IngressToMiddleLink_In"); + } + portConnect(middle_router, "CK", "CK"); + for(unsigned int i = 0; i < middle_router_number_input_ports; ++i) + { + createNet("MiddleRouter_In" + (String)i, makeNetIndex(0, number_bits_per_flit-1)); + for (unsigned int j = 0; j < number_bits_per_flit; ++j) + assignVirtualFanout("MiddleRouter_In" + (String)i, makeNetIndex(j), "IngressToMiddleLink_Out", makeNetIndex(j)); + portConnect(middle_router, "FlitIn" + (String)i, "MiddleRouter_In" + (String)i); + } + for(unsigned int i = 0; i < middle_router_number_output_ports; ++i) + { + // VFI + portConnect(middle_router, "FlitOut" + (String)i, "MiddleToEgressLink_In"); + } + portConnect(egress_router, "CK", "CK"); + for(unsigned int i = 0; i < egress_router_number_input_ports; ++i) + { + createNet("EgressRouter_In" + (String)i, makeNetIndex(0, number_bits_per_flit-1)); + for (unsigned int j = 0; j < number_bits_per_flit; ++j) + assignVirtualFanout("EgressRouter_In" + (String)i, makeNetIndex(j), "MiddleToEgressLink_Out", makeNetIndex(j)); + portConnect(egress_router, "FlitIn" + (String)i, "EgressRouter_In" + (String)i); + } + for(unsigned int i = 0; i < egress_router_number_output_ports; ++i) + { + // VFI + portConnect(egress_router, "FlitOut" + (String)i, "EgressToOutputLink_In"); + } + + // Create area, power, and event results + createElectricalResults(); + createElectricalEventResult("AvgUnicast"); + createElectricalEventResult("AvgBroadcast"); + addNddPowerResult(new Result("Laser")); + addNddPowerResult(new Result("RingTuning")); + addAreaResult(new Result("Photonic")); + + // Add all instances + addSubInstances(ingress_router, number_ingress_routers); + addElectricalSubResults(ingress_router, number_ingress_routers); + addSubInstances(middle_router, number_middle_routers); + addElectricalSubResults(middle_router, number_middle_routers); + addSubInstances(egress_router, number_egress_routers); + addElectricalSubResults(egress_router, number_egress_routers); + addSubInstances(input_to_ingress_link, number_input_to_ingress_links); + addElectricalSubResults(input_to_ingress_link, number_input_to_ingress_links); + addSubInstances(ingress_to_middle_link, number_ingress_to_middle_links); + addElectricalSubResults(ingress_to_middle_link, number_ingress_to_middle_links); + getAreaResult("Photonic")->addSubResult(ingress_to_middle_link->getAreaResult("Photonic"), "IngressToMiddleLink", number_ingress_to_middle_links); + getNddPowerResult("Laser")->addSubResult(ingress_to_middle_link->getNddPowerResult("Laser"), "IngressToMiddleLink", number_ingress_to_middle_links); + getNddPowerResult("RingTuning")->addSubResult(ingress_to_middle_link->getNddPowerResult("RingTuning"), "IngressToMiddleLink", number_ingress_to_middle_links); + addSubInstances(middle_to_egress_link, number_middle_to_egress_links); + addElectricalSubResults(middle_to_egress_link, number_middle_to_egress_links); + getAreaResult("Photonic")->addSubResult(middle_to_egress_link->getAreaResult("Photonic"), "MiddletoEgressLink", number_middle_to_egress_links); + getNddPowerResult("Laser")->addSubResult(middle_to_egress_link->getNddPowerResult("Laser"), "MiddleToEgressLink", number_middle_to_egress_links); + getNddPowerResult("RingTuning")->addSubResult(middle_to_egress_link->getNddPowerResult("RingTuning"), "MiddleToEgressLink", number_middle_to_egress_links); + addSubInstances(egress_to_output_link, number_egress_to_output_links); + addElectricalSubResults(egress_to_output_link, number_egress_to_output_links); + + // Update unicast event + Result* avg_unicast_event = getEventResult("AvgUnicast"); + avg_unicast_event->addSubResult(input_to_ingress_link->getEventResult("Send"), "InputToIngressLink", 1.0); + if(ingress_router->hasEventResult("WriteBuffer")) + { + avg_unicast_event->addSubResult(ingress_router->getEventResult("WriteBuffer"), "IngressRouter", 1.0); + } + if(ingress_router->hasEventResult("ReadBuffer")) + { + avg_unicast_event->addSubResult(ingress_router->getEventResult("ReadBuffer"), "IngressRouter", 1.0); + } + avg_unicast_event->addSubResult(ingress_router->getEventResult("TraverseCrossbar->Multicast1"), "IngressRouter", 1.0); + avg_unicast_event->addSubResult(ingress_to_middle_link->getEventResult("Send"), "IngressToMiddleLink", 1.0); + if(middle_router->hasEventResult("WriteBuffer")) + { + avg_unicast_event->addSubResult(middle_router->getEventResult("WriteBuffer"), "MiddleRouter", 1.0); + } + if(middle_router->hasEventResult("ReadBuffer")) + { + avg_unicast_event->addSubResult(middle_router->getEventResult("ReadBuffer"), "MiddleRouter", 1.0); + } + avg_unicast_event->addSubResult(middle_router->getEventResult("TraverseCrossbar->Multicast1"), "MiddleRouter", 1.0); + avg_unicast_event->addSubResult(middle_to_egress_link->getEventResult("Send"), "MiddleToEgressLink", 1.0); + if(egress_router->hasEventResult("WriteBuffer")) + { + avg_unicast_event->addSubResult(egress_router->getEventResult("WriteBuffer"), "EgressRouter", 1.0); + } + if(egress_router->hasEventResult("ReadBuffer")) + { + avg_unicast_event->addSubResult(egress_router->getEventResult("ReadBuffer"), "EgressRouter", 1.0); + } + avg_unicast_event->addSubResult(egress_router->getEventResult("TraverseCrossbar->Multicast1"), "EgressRouter", 1.0); + avg_unicast_event->addSubResult(egress_to_output_link->getEventResult("Send"), "EgressToOutputLink", 1.0); + + // Update broadcast event + Result* avg_broadcast_event = getEventResult("AvgBroadcast"); + avg_broadcast_event->addSubResult(input_to_ingress_link->getEventResult("Send"), "InputToIngressLink", 1.0); + if(ingress_router->hasEventResult("WriteBuffer")) + { + avg_broadcast_event->addSubResult(ingress_router->getEventResult("WriteBuffer"), "IngressRouter", 1.0); + } + if(ingress_router->hasEventResult("ReadBuffer")) + { + avg_broadcast_event->addSubResult(ingress_router->getEventResult("ReadBuffer"), "IngressRouter", 1.0); + } + avg_broadcast_event->addSubResult(ingress_router->getEventResult("TraverseCrossbar->Multicast1"), "IngressRouter", 1.0); + avg_broadcast_event->addSubResult(ingress_to_middle_link->getEventResult("Send"), "IngressToMiddleLink", 1.0); + if(middle_router->hasEventResult("WriteBuffer")) + { + avg_broadcast_event->addSubResult(middle_router->getEventResult("WriteBuffer"), "MiddleRouter", 1.0); + } + if(middle_router->hasEventResult("ReadBuffer")) + { + avg_broadcast_event->addSubResult(middle_router->getEventResult("ReadBuffer"), "MiddleRouter", 1.0); + } + avg_broadcast_event->addSubResult(middle_router->getEventResult("TraverseCrossbar->Multicast1"), "MiddleRouter", 1.0); + avg_broadcast_event->addSubResult(middle_to_egress_link->getEventResult("Send"), "MiddleToEgressLink", number_egress_routers); + if(egress_router->hasEventResult("WriteBuffer")) + { + avg_broadcast_event->addSubResult(egress_router->getEventResult("WriteBuffer"), "EgressRouter", number_egress_routers); + } + if(egress_router->hasEventResult("ReadBuffer")) + { + avg_broadcast_event->addSubResult(egress_router->getEventResult("ReadBuffer"), "EgressRouter", number_egress_routers); + } + avg_broadcast_event->addSubResult(egress_router->getEventResult("TraverseCrossbar->Multicast" + (String)number_egress_routers), "EgressRouter", 1.0); + avg_broadcast_event->addSubResult(egress_to_output_link->getEventResult("Send"), "EgressToOutputLink", number_output_sites); + return; + } + + void PhotonicClos::updateModel() + { + // Assumes waveguide runs adjacent to ingress and egress routers + // Assumes input sites belonging to each ingress router are centered around the ingress router + // Assumes middle routers are distributed around the chip adjacent to the main waveguide + // Assumes output sites belonging to each egress router are centered around the egress router + + // Get properties + double input_site_pitch = getProperty("InputSitePitch").toDouble(); + double output_site_pitch = getProperty("OutputSitePitch").toDouble(); + double clock_freq = getParameter("Frequency"); + const double swsr_opt_util = getProperty("SWSR->OptUtil"); + + ASSERT(input_site_pitch > 0, "[Error] " + getInstanceName() + + " -> Input site pitch must be > 0!"); + ASSERT(output_site_pitch > 0, "[Error] " + getInstanceName() + + " -> Output site pitch must be > 0!"); + + unsigned int number_input_sites_per_ingress_router = getGenProperties()->get("NumberInputSitesPerIngressRouter"); + unsigned int number_ingress_routers = getParameter("NumberIngressRouters"); + unsigned int number_output_sites_per_egress_router = getGenProperties()->get("NumberOutputSitesPerEgressRouter"); + unsigned int number_egress_routers = getParameter("NumberEgressRouters"); + double delay = 1.0 / clock_freq; + + //Calculate the length of the waveguide + double input_to_ingress_link_length = input_site_pitch * (sqrt(number_input_sites_per_ingress_router) - 1.0); + double input_to_ingress_link_delay = delay * 0.8; + double ingress_to_middle_link_length = input_site_pitch * (sqrt(number_input_sites_per_ingress_router) * number_ingress_routers); + double middle_to_egress_link_length = output_site_pitch * (sqrt(number_output_sites_per_egress_router) * number_egress_routers); + double egress_to_output_link_length = output_site_pitch * (sqrt(number_output_sites_per_egress_router) - 1.0); + double egress_to_output_link_delay = delay * 0.8; + double ingress_router_delay = delay; + double middle_router_delay = delay; + double egress_router_delay = delay; + + Model* input_to_ingress_link = getSubInstance("InputToIngressLink"); + input_to_ingress_link->setProperty("WireLength", input_to_ingress_link_length); + input_to_ingress_link->setProperty("Delay", input_to_ingress_link_delay); + input_to_ingress_link->setProperty("IsKeepParity", "TRUE"); + input_to_ingress_link->update(); + + Model* ingress_to_middle_link = getSubInstance("IngressToMiddleLink"); + ingress_to_middle_link->setProperty("Length", ingress_to_middle_link_length); + ingress_to_middle_link->setProperty("OptUtil", swsr_opt_util); + ingress_to_middle_link->update(); + + Model* middle_to_egress_link = getSubInstance("MiddleToEgressLink"); + middle_to_egress_link->setProperty("Length", middle_to_egress_link_length); + middle_to_egress_link->setProperty("OptUtil", swsr_opt_util); + middle_to_egress_link->update(); + + Model* egress_to_output_link = getSubInstance("EgressToOutputLink"); + egress_to_output_link->setProperty("WireLength", egress_to_output_link_length); + egress_to_output_link->setProperty("Delay", egress_to_output_link_delay); + egress_to_output_link->setProperty("IsKeepParity", "TRUE"); + egress_to_output_link->update(); + + ElectricalModel* ingress_router = (ElectricalModel*)getSubInstance("IngressRouter"); + ingress_router->update(); + ElectricalTimingTree ingress_router_timing_tree("IngressRouter", ingress_router); + ingress_router_timing_tree.performTimingOpt(ingress_router->getNet("CK"), ingress_router_delay); + + ElectricalModel* middle_router = (ElectricalModel*)getSubInstance("MiddleRouter"); + middle_router->update(); + ElectricalTimingTree middle_router_timing_tree("MiddleRouter", middle_router); + middle_router_timing_tree.performTimingOpt(middle_router->getNet("CK"), middle_router_delay); + + ElectricalModel* egress_router = (ElectricalModel*)getSubInstance("EgressRouter"); + egress_router->update(); + ElectricalTimingTree egress_router_timing_tree("EgressRouter", egress_router); + egress_router_timing_tree.performTimingOpt(egress_router->getNet("CK"), egress_router_delay); + + return; + } + + void PhotonicClos::propagateTransitionInfo() + { + // Get parameters + double clock_freq = getParameter("Frequency"); + double swsr_link_data_rate = getParameter("SWSR->LinkDataRate"); + + // Get properties + unsigned int ingress_router_number_input_ports = getGenProperties()->get("IngressRouter->NumberInputPorts"); + unsigned int middle_router_number_input_ports = getGenProperties()->get("MiddleRouter->NumberInputPorts"); + unsigned int egress_router_number_input_ports = getGenProperties()->get("EgressRouter->NumberInputPorts"); + + ElectricalModel* input_to_ingress_link = (ElectricalModel*)getSubInstance("InputToIngressLink"); + assignPortTransitionInfo(input_to_ingress_link, "In", TransitionInfo(0.25, 0.25, 0.25)); + input_to_ingress_link->use(); + + ElectricalModel* ingress_to_middle_link = (ElectricalModel*)getSubInstance("IngressToMiddleLink"); + assignPortTransitionInfo(ingress_to_middle_link, "LinkCK", TransitionInfo(0.0, (double) clock_freq / (swsr_link_data_rate * 2.0), 0.0)); + assignPortTransitionInfo(ingress_to_middle_link, "In", TransitionInfo(0.25, 0.25, 0.25)); + ingress_to_middle_link->use(); + + ElectricalModel* middle_to_egress_link = (ElectricalModel*)getSubInstance("MiddleToEgressLink"); + assignPortTransitionInfo(middle_to_egress_link, "LinkCK", TransitionInfo(0.0, (double) clock_freq / (swsr_link_data_rate * 2.0), 0.0)); + assignPortTransitionInfo(middle_to_egress_link, "In", TransitionInfo(0.25, 0.25, 0.25)); + middle_to_egress_link->use(); + + ElectricalModel* egress_to_output_link = (ElectricalModel*)getSubInstance("EgressToOutputLink"); + assignPortTransitionInfo(egress_to_output_link, "In", TransitionInfo(0.25, 0.25, 0.25)); + egress_to_output_link->use(); + + ElectricalModel* ingress_router = (ElectricalModel*)getSubInstance("IngressRouter"); + for(unsigned int i = 0; i < ingress_router_number_input_ports; ++i) + { + assignPortTransitionInfo(ingress_router, "FlitIn" + (String)i, TransitionInfo(0.25, 0.25, 0.25)); + } + assignPortTransitionInfo(ingress_router, "CK", TransitionInfo(0.0, 1.0, 0.0)); + ingress_router->getGenProperties()->set("UseModelEvent", ""); + ingress_router->use(); + + ElectricalModel* middle_router = (ElectricalModel*)getSubInstance("MiddleRouter"); + for(unsigned int i = 0; i < middle_router_number_input_ports; ++i) + { + assignPortTransitionInfo(middle_router, "FlitIn" + (String)i, TransitionInfo(0.25, 0.25, 0.25)); + } + assignPortTransitionInfo(middle_router, "CK", TransitionInfo(0.0, 1.0, 0.0)); + middle_router->getGenProperties()->set("UseModelEvent", ""); + middle_router->use(); + + ElectricalModel* egress_router = (ElectricalModel*)getSubInstance("EgressRouter"); + for(unsigned int i = 0; i < egress_router_number_input_ports; ++i) + { + assignPortTransitionInfo(egress_router, "FlitIn" + (String)i, TransitionInfo(0.25, 0.25, 0.25)); + } + assignPortTransitionInfo(egress_router, "CK", TransitionInfo(0.0, 1.0, 0.0)); + egress_router->getGenProperties()->set("UseModelEvent", ""); + egress_router->use(); + + return; + } +} // namespace DSENT + diff --git a/ext/dsent/model/network/PhotonicClos.h b/ext/dsent/model/network/PhotonicClos.h new file mode 100644 index 000000000..814885dd7 --- /dev/null +++ b/ext/dsent/model/network/PhotonicClos.h @@ -0,0 +1,37 @@ +#ifndef __DSENT_MODEL_NETWORK_PHOTONIC_CLOS_H__ +#define __DSENT_MODEL_NETWORK_PHOTONIC_CLOS_H__ + +#include "util/CommonType.h" +#include "model/ElectricalModel.h" + +namespace DSENT +{ + /** + * \brief An 3-stage clos network implemented with photonic router-to-router links + */ + class PhotonicClos : public ElectricalModel + { + public: + PhotonicClos(const String& instance_name_, const TechModel* tech_model_); + virtual ~PhotonicClos(); + + public: + // Set a list of properties' name needed to construct model + void initParameters(); + // Set a list of properties' name needed to construct model + void initProperties(); + + // Clone and return a new instance + virtual PhotonicClos* clone() const; + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void propagateTransitionInfo(); + + }; +} // namespace DSENT + +#endif // __DSENT_MODEL_NETWORK_PHOTONIC_CLOS_H__ + diff --git a/ext/dsent/model/optical/GatedLaserSource.cc b/ext/dsent/model/optical/GatedLaserSource.cc new file mode 100644 index 000000000..e32474daf --- /dev/null +++ b/ext/dsent/model/optical/GatedLaserSource.cc @@ -0,0 +1,106 @@ +#include "model/optical/GatedLaserSource.h" + +#include "model/optical_graph/OpticalWaveguide.h" +#include "model/optical_graph/OpticalWavelength.h" +#include "model/optical_graph/OpticalLaser.h" +#include "model/optical_graph/OpticalGraph.h" + +namespace DSENT +{ + GatedLaserSource::GatedLaserSource(const String& instance_name_, const TechModel* tech_model_) + : OpticalModel(instance_name_, tech_model_) + { + initParameters(); + initProperties(); + } + + GatedLaserSource::~GatedLaserSource() + {} + + void GatedLaserSource::initParameters() + { + addParameterName("OutStart"); + addParameterName("OutEnd"); + addParameterName("MaxDetectors"); + return; + } + + void GatedLaserSource::initProperties() + { + addPropertyName("OptUtil", 1.0); + addPropertyName("LaserEventTime"); + return; + } + + void GatedLaserSource::constructModel() + { + // Create Area result + Result* area_result = new AtomicResult("Photonic"); + addAreaResult(area_result); + // Create NDD power result + Result* energy_result = new AtomicResult("Laser"); + addEventResult(energy_result); + + // Get parameters + WavelengthGroup laser_wavelengths = makeWavelengthGroup(getParameter("OutStart"), getParameter("OutEnd")); + + // Create optical ports + createOpticalOutputPort( "Out", laser_wavelengths); + // Create the filter + createLaser( "Laser", laser_wavelengths); + OpticalLaser* laser = getLaser("Laser"); + // Connect the laser to the output + laser->addDownstreamNode(getWaveguide("Out")); + } + + void GatedLaserSource::updateModel() + { + // Get properties + double laser_efficiency = getTechModel()->get("Laser->CW->Efficiency"); + double laser_area = getTechModel()->get("Laser->CW->Area"); + double laser_diode_loss = getTechModel()->get("Laser->CW->LaserDiodeLoss"); + + // Get parameters + WavelengthGroup laser_wavelengths = makeWavelengthGroup(getParameter("OutStart"), getParameter("OutEnd")); + unsigned int number_wavelengths = laser_wavelengths.second - laser_wavelengths.first + 1; + // Update losses + OpticalLaser* laser = getLaser("Laser"); + laser->setLoss(laser_diode_loss); + laser->setEfficiency(laser_efficiency); + // Update area + getAreaResult("Photonic")->setValue(laser_area * number_wavelengths); + } + + void GatedLaserSource::evaluateModel() + { + // Get parameters + unsigned int max_detectors = getParameter("MaxDetectors"); + double laser_event_time = getProperty("LaserEventTime"); + WavelengthGroup laser_wavelengths = makeWavelengthGroup(getParameter("OutStart"), getParameter("OutEnd")); + + // Get properties + double opt_util = getProperty("OptUtil"); + + // Create optical graph object + OpticalGraph* optical_graph = new OpticalGraph("LaserTrace", this); + // Ask optical graph object to perform power optimization + bool success = optical_graph->performPowerOpt(getLaser("Laser"), laser_wavelengths, max_detectors, opt_util); + if (!success) + { + Log::printLine(std::cerr, "[Warning] " + getInstanceName() + + " -> Wavelengths contains data paths with no possible modulator configurations!"); + } + // Trace the wavelengths the laser is outputting to find the output + // power needed by the laser + OpticalWavelength* wavelength = optical_graph->traceWavelength(laser_wavelengths, getLaser("Laser")); + // Calculate the power needed by the wavelength + double laser_power = wavelength->getLaserPower(max_detectors); + // Calculate NDD power + getEventResult("Laser")->setValue(laser_power * laser_event_time); + + delete wavelength; + delete optical_graph; + } + +} // namespace DSENT + diff --git a/ext/dsent/model/optical/GatedLaserSource.h b/ext/dsent/model/optical/GatedLaserSource.h new file mode 100644 index 000000000..b6413b047 --- /dev/null +++ b/ext/dsent/model/optical/GatedLaserSource.h @@ -0,0 +1,33 @@ +#ifndef __DSENT_MODEL_OPTICAL_GATEDLASERSOURCE_H__ +#define __DSENT_MODEL_OPTICAL_GATEDLASERSOURCE_H__ + +#include "util/CommonType.h" +#include "model/OpticalModel.h" + +namespace DSENT +{ + // A laser source that outputs some number of wavelengths. This laser + // full on/off power gating, thus all power are event-based energies + class GatedLaserSource : public OpticalModel + { + public: + GatedLaserSource(const String& instance_name_, const TechModel* tech_model_); + virtual ~GatedLaserSource(); + + public: + // Set a list of properties' name needed to construct model + void initParameters(); + // Set a list of properties' name needed to construct model + void initProperties(); + + protected: + // Build the model + void constructModel(); + void updateModel(); + void evaluateModel(); + + }; // class GatedLaserSource +} // namespace DSENT + +#endif // __DSENT_MODEL_OPTICAL_GATEDLASERSOURCE_H__ + diff --git a/ext/dsent/model/optical/LaserSource.cc b/ext/dsent/model/optical/LaserSource.cc new file mode 100644 index 000000000..e55de8cf7 --- /dev/null +++ b/ext/dsent/model/optical/LaserSource.cc @@ -0,0 +1,105 @@ +#include "model/optical/LaserSource.h" + +#include "model/optical_graph/OpticalWaveguide.h" +#include "model/optical_graph/OpticalWavelength.h" +#include "model/optical_graph/OpticalLaser.h" +#include "model/optical_graph/OpticalGraph.h" + +namespace DSENT +{ + LaserSource::LaserSource(const String& instance_name_, const TechModel* tech_model_) + : OpticalModel(instance_name_, tech_model_) + { + initParameters(); + initProperties(); + } + + LaserSource::~LaserSource() + {} + + void LaserSource::initParameters() + { + addParameterName("OutStart"); + addParameterName("OutEnd"); + addParameterName("MaxDetectors"); + return; + } + + void LaserSource::initProperties() + { + addPropertyName("OptUtil", 1.0); + return; + } + + void LaserSource::constructModel() + { + // Create Area result + Result* area_result = new AtomicResult("Photonic"); + addAreaResult(area_result); + // Create NDD power result + Result* power_result = new AtomicResult("Laser"); + addNddPowerResult(power_result); + + // Get parameters + WavelengthGroup laser_wavelengths = makeWavelengthGroup(getParameter("OutStart"), getParameter("OutEnd")); + + // Create optical ports + createOpticalOutputPort( "Out", laser_wavelengths); + // Create the filter + createLaser( "Laser", laser_wavelengths); + OpticalLaser* laser = getLaser("Laser"); + // Connect the laser to the output + laser->addDownstreamNode(getWaveguide("Out")); + } + + void LaserSource::updateModel() + { + // Get properties + double laser_efficiency = getTechModel()->get("Laser->CW->Efficiency").toDouble(); + double laser_area = getTechModel()->get("Laser->CW->Area").toDouble(); + double laser_diode_loss = getTechModel()->get("Laser->CW->LaserDiodeLoss"); + + // Get parameters + WavelengthGroup laser_wavelengths = makeWavelengthGroup(getParameter("OutStart"), getParameter("OutEnd")); + unsigned int number_wavelengths = laser_wavelengths.second - laser_wavelengths.first + 1; + // Update losses + OpticalLaser* laser = getLaser("Laser"); + laser->setLoss(laser_diode_loss); + laser->setEfficiency(laser_efficiency); + // Update area + getAreaResult("Photonic")->setValue(laser_area * number_wavelengths); + } + + void LaserSource::evaluateModel() + { + // Get parameters + unsigned int max_detectors = getParameter("MaxDetectors").toUInt(); + WavelengthGroup laser_wavelengths = makeWavelengthGroup(getParameter("OutStart"), getParameter("OutEnd")); + + // Get properties + double opt_util = getProperty("OptUtil"); + + // Create optical graph object + OpticalGraph* optical_graph = new OpticalGraph("LaserTrace", this); + // Ask optical graph object to perform power optimization + bool success = optical_graph->performPowerOpt(getLaser("Laser"), laser_wavelengths, max_detectors, opt_util); + if (!success) + { + Log::printLine(std::cerr, "[Warning] " + getInstanceName() + + " -> Wavelengths contains data paths with no possible modulator configurations!"); + } + // Trace the wavelengths the laser is outputting to find the output + // power needed by the laser + OpticalWavelength* wavelength = optical_graph->traceWavelength(laser_wavelengths, getLaser("Laser")); + // Calculate the power needed by the wavelength + double laser_power = wavelength->getLaserPower(max_detectors); + + // Calculate NDD power + getNddPowerResult("Laser")->setValue(laser_power); + + delete wavelength; + delete optical_graph; + } + +} // namespace DSENT + diff --git a/ext/dsent/model/optical/LaserSource.h b/ext/dsent/model/optical/LaserSource.h new file mode 100644 index 000000000..92c7658d5 --- /dev/null +++ b/ext/dsent/model/optical/LaserSource.h @@ -0,0 +1,33 @@ +#ifndef __DSENT_MODEL_OPTICAL_LASERSOURCE_H__ +#define __DSENT_MODEL_OPTICAL_LASERSOURCE_H__ + +#include "util/CommonType.h" +#include "model/OpticalModel.h" + +namespace DSENT +{ + // A laser source that outputs some number of wavelengths. This laser cannot + // be gated on/off at will and thus constitutes an NDD Power consumer + class LaserSource : public OpticalModel + { + public: + LaserSource(const String& instance_name_, const TechModel* tech_model_); + virtual ~LaserSource(); + + public: + // Set a list of properties' name needed to construct model + void initParameters(); + // Set a list of properties' name needed to construct model + void initProperties(); + + protected: + // Build the model + void constructModel(); + void updateModel(); + void evaluateModel(); + + }; // class LaserSource +} // namespace DSENT + +#endif // __DSENT_MODEL_OPTICAL_LASERSOURCE_H__ + diff --git a/ext/dsent/model/optical/OpticalLinkBackendRx.cc b/ext/dsent/model/optical/OpticalLinkBackendRx.cc new file mode 100644 index 000000000..3a65cee62 --- /dev/null +++ b/ext/dsent/model/optical/OpticalLinkBackendRx.cc @@ -0,0 +1,364 @@ +#include "model/optical/OpticalLinkBackendRx.h" + +#include "util/Constants.h" +#include "model/PortInfo.h" +#include "model/TransitionInfo.h" +#include "model/EventInfo.h" +#include "model/electrical/DemuxTreeDeserializer.h" +#include "model/electrical/BarrelShifter.h" +#include "model/electrical/Multiplexer.h" +#include <cmath> + +namespace DSENT +{ + // TODO: Kind of don't like the way thermal tuning is written here. Maybe will switch + // to curve fitting the CICC paper, which uses results from a monte-carlo sim. Also, there is + // redundant code between this one and the tx one... + + OpticalLinkBackendRx::OpticalLinkBackendRx(const String& instance_name_, const TechModel* tech_model_) + : ElectricalModel(instance_name_, tech_model_) + { + initParameters(); + initProperties(); + } + + OpticalLinkBackendRx::~OpticalLinkBackendRx() + {} + + void OpticalLinkBackendRx::initParameters() + { + addParameterName("OutBits"); + addParameterName("CoreDataRate"); + addParameterName("LinkDataRate"); + addParameterName("RingTuningMethod"); + addParameterName("BitDuplicate"); + return; + } + + void OpticalLinkBackendRx::initProperties() + { + return; + } + + void OpticalLinkBackendRx::constructModel() + { + unsigned int out_bits = getParameter("OutBits"); + double core_data_rate = getParameter("CoreDataRate"); + double link_data_rate = getParameter("LinkDataRate"); + const String& tuning_method = getParameter("RingTuningMethod"); + bool bit_duplicate = getParameter("BitDuplicate"); + + // Calculate deserialization ratio + unsigned int deserialization_ratio = (unsigned int) floor(link_data_rate / core_data_rate); + ASSERT(deserialization_ratio == link_data_rate / core_data_rate, + "[Error] " + getInstanceName() + " -> Cannot have non-integer deserialization ratios!"); + ASSERT((deserialization_ratio & (deserialization_ratio - 1)) == 0, + "[Error] " + getInstanceName() + " -> Deserialization ratio must be a power of 2"); + + // Calculate output width + unsigned int in_bits = out_bits / deserialization_ratio; + ASSERT(out_bits >= deserialization_ratio, "[Error] " + getInstanceName() + + " -> Output width must be >= deserialization ratio!"); + ASSERT(floor((double) out_bits / deserialization_ratio) == in_bits, + "[Error] " + getInstanceName() + " -> Output width must be a multiple of the serialization ratio!"); + + getGenProperties()->set("DeserializationRatio", deserialization_ratio); + getGenProperties()->set("InBits", in_bits); + + // Create ports + createInputPort("In", makeNetIndex(0, in_bits-1)); + createInputPort("LinkCK"); + createOutputPort("Out", makeNetIndex(0, out_bits-1)); + + //Create energy, power, and area results + createElectricalResults(); + // Create ring heating power cost + addNddPowerResult(new AtomicResult("RingTuning")); + // Create process bits event + createElectricalEventResult("ProcessBits"); + getEventInfo("ProcessBits")->setTransitionInfo("LinkCK", TransitionInfo(0.0, (double) deserialization_ratio / 2.0, 0.0)); + // Set conditions during idle state + getEventInfo("Idle")->setStaticTransitionInfos(); + getEventInfo("Idle")->setTransitionInfo("LinkCK", TransitionInfo(0.0, (double) deserialization_ratio / 2.0, 0.0)); + + // Create deserializer + const String& deserializer_name = "Deserializer"; + DemuxTreeDeserializer* deserializer = new DemuxTreeDeserializer(deserializer_name, getTechModel()); + deserializer->setParameter("OutBits", out_bits); + deserializer->setParameter("InDataRate", link_data_rate); + deserializer->setParameter("OutDataRate", core_data_rate); + deserializer->setParameter("BitDuplicate", bit_duplicate); + deserializer->construct(); + + addSubInstances(deserializer, 1.0); + addElectricalSubResults(deserializer, 1.0); + getEventResult("ProcessBits")->addSubResult(deserializer->getEventResult("Deserialize"), deserializer_name, 1.0); + + if ((tuning_method == "ThermalWithBitReshuffle") || (tuning_method == "ElectricalAssistWithBitReshuffle")) + { + // If a bit reshuffling backend is present, create the reshuffling backend + unsigned int reorder_degree = getBitReorderDegree(); + + // Create intermediate nets + createNet("ReorderIn", makeNetIndex(0, in_bits+reorder_degree-1)); + assign("ReorderIn", makeNetIndex(0, in_bits-1), "In"); + assign("ReorderIn", makeNetIndex(in_bits, in_bits+reorder_degree-1), "ReorderIn", makeNetIndex(0, reorder_degree-1)); + createNet("DeserializerIn", makeNetIndex(0, in_bits-1)); + createNet("BarrelShiftIn", makeNetIndex(0, out_bits-1)); + + // Create bit reorder muxes + const String& reorder_mux_name = "ReorderMux"; + Multiplexer* reorder_mux = new Multiplexer(reorder_mux_name, getTechModel()); + reorder_mux->setParameter("NumberBits", in_bits); + reorder_mux->setParameter("NumberInputs", reorder_degree); + reorder_mux->setParameter("BitDuplicate", bit_duplicate); + reorder_mux->construct(); + + // Create barrelshifter + unsigned int shift_index_min = (unsigned int)ceil(log2(deserialization_ratio)); + unsigned int shift_index_max = std::max(shift_index_min, (unsigned int) ceil(log2(out_bits)) - 1); + + // Remember some things + getGenProperties()->set("ReorderDegree", reorder_degree); + getGenProperties()->set("ShiftIndexMin", shift_index_min); + getGenProperties()->set("ShiftIndexMax", shift_index_max); + + const String& barrel_shift_name = "BarrelShifter"; + BarrelShifter* barrel_shift = new BarrelShifter(barrel_shift_name, getTechModel()); + barrel_shift->setParameter("NumberBits", out_bits); + barrel_shift->setParameter("ShiftIndexMax", shift_index_max); + barrel_shift->setParameter("ShiftIndexMin", shift_index_min); + barrel_shift->setParameter("BitDuplicate", bit_duplicate); + barrel_shift->construct(); + + // Connect serializer + portConnect(deserializer, "In", "DeserializerIn"); + portConnect(deserializer, "Out", "BarrelShiftIn"); + portConnect(deserializer, "InCK", "LinkCK"); + + // Connect barrelshifter + // TODO: Connect barrelshift shifts! + portConnect(barrel_shift, "In", "BarrelShiftIn"); + portConnect(barrel_shift, "Out", "Out"); + + // Connect bit reorder muxes + // TODO: Connect re-order multiplex select signals! + for (unsigned int i = 0; i < reorder_degree; i++) + portConnect(reorder_mux, "In" + (String) i, "ReorderIn", makeNetIndex(i, i+in_bits-1)); + portConnect(reorder_mux, "Out", "DeserializerIn"); + + addSubInstances(barrel_shift, 1.0); + addSubInstances(reorder_mux, 1.0); + addElectricalSubResults(barrel_shift, 1.0); + addElectricalSubResults(reorder_mux, 1.0); + getEventResult("ProcessBits")->addSubResult(barrel_shift->getEventResult("BarrelShift"), barrel_shift_name, 1.0); + getEventResult("ProcessBits")->addSubResult(reorder_mux->getEventResult("Mux"), reorder_mux_name, 1.0); + } + else if ((tuning_method == "FullThermal") || (tuning_method == "AthermalWithTrim")) + { + // If no bit reshuffling backend is present, then just connect deserializer up + portConnect(deserializer, "In", "In"); + portConnect(deserializer, "Out", "Out"); + portConnect(deserializer, "InCK", "LinkCK"); + } + else + { + ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown ring tuning method '" + tuning_method + "'!"); + } + + return; + } + + void OpticalLinkBackendRx::updateModel() + { + // Update everyone + Model::updateModel(); + // Update ring tuning power + getNddPowerResult("RingTuning")->setValue(getRingTuningPower()); + return; + } + + void OpticalLinkBackendRx::propagateTransitionInfo() + { + // Get parameters + const String& tuning_method = getParameter("RingTuningMethod");; + + // Get properties + + // Update the deserializer + if ((tuning_method == "ThermalWithBitReshuffle") || (tuning_method == "ElectricalAssistWithBitReshuffle")) + { + // Get generated properties + unsigned int reorder_degree = getGenProperties()->get("ReorderDegree"); + unsigned int shift_index_min = getGenProperties()->get("ShiftIndexMin"); + unsigned int shift_index_max = getGenProperties()->get("ShiftIndexMax"); + + // Reorder mux shift select bits + unsigned int reorder_sel_bits = (unsigned int)ceil(log2(reorder_degree)); + + // Create bit reorder muxes + const String& reorder_mux_name = "ReorderMux"; + ElectricalModel* reorder_mux = (ElectricalModel*) getSubInstance(reorder_mux_name); + for (unsigned int i = 0; i < reorder_degree; ++i) + propagatePortTransitionInfo(reorder_mux, "In" + (String) i, "In"); + // Set select transitions to be 0, since these are statically configured + for (unsigned int i = 0; i < reorder_sel_bits; ++i) + reorder_mux->getInputPort("Sel" + (String) i)->setTransitionInfo(TransitionInfo(0.5, 0.0, 0.5)); + reorder_mux->use(); + + // Update the deserializer + ElectricalModel* deserializer = (ElectricalModel*) getSubInstance("Deserializer"); + propagatePortTransitionInfo(deserializer, "In", reorder_mux, "Out"); + propagatePortTransitionInfo(deserializer, "InCK", "LinkCK"); + deserializer->use(); + + // Update barrel shifter + const String& barrel_shift_name = "BarrelShifter"; + ElectricalModel* barrel_shift = (ElectricalModel*) getSubInstance(barrel_shift_name); + propagatePortTransitionInfo(barrel_shift, "In", deserializer, "Out"); + // Set shift transitions to be very low (since it is affected by slow temperature time constants) + for (unsigned int i = shift_index_min; i <= shift_index_max; ++i) + barrel_shift->getInputPort("Shift" + (String) i)->setTransitionInfo(TransitionInfo(0.499, 0.001, 0.499)); + barrel_shift->use(); + + // Set output transition info + propagatePortTransitionInfo("Out", barrel_shift, "Out"); + } + else if ((tuning_method == "FullThermal") || (tuning_method == "AthermalWithTrim")) + { + // Update the deserializer + ElectricalModel* deserializer = (ElectricalModel*) getSubInstance("Deserializer"); + propagatePortTransitionInfo(deserializer, "In", "In"); + propagatePortTransitionInfo(deserializer, "InCK", "LinkCK"); + deserializer->use(); + + // Set output transition info + propagatePortTransitionInfo("Out", deserializer, "Out"); + } + else + { + ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown ring tuning method '" + tuning_method + "'!"); + } + + return; + } + + double OpticalLinkBackendRx::getRingTuningPower() + { + // Get properties + const String& tuning_method = getParameter("RingTuningMethod");; + unsigned int number_rings = getGenProperties()->get("InBits"); + + // Get tech model parameters + double R = getTechModel()->get("Ring->Radius"); + double n_g = getTechModel()->get("Ring->GroupIndex"); + double heating_efficiency = getTechModel()->get("Ring->HeatingEfficiency"); + // This can actually be derived if we know thermo-optic coefficient (delta n / delta T) + double tuning_efficiency = getTechModel()->get("Ring->TuningEfficiency"); + double sigma_r_local = getTechModel()->get("Ring->LocalVariationSigma"); + double sigma_r_systematic = getTechModel()->get("Ring->SystematicVariationSigma"); + double T_max = getTechModel()->get("Ring->TemperatureMax"); + double T_min = getTechModel()->get("Ring->TemperatureMin"); + double T = getTechModel()->get("Temperature"); + + // Get constants + double c = Constants::c; + double pi = Constants::pi; + + double tuning_power = 0.0; + + if (tuning_method == "ThermalWithBitReshuffle") + { + // When an electrical backend is present, rings only have to tune to the nearest channel + // This can be approximated as each ring tuning to something exactly 1 channel away + + // Setup calculations + double L = 2 * pi * R; // Optical length + double FSR = c / (n_g * L); // Free spectral range + double freq_sep = FSR / number_rings; // Channel separation + + // Calculate tuning power + tuning_power = number_rings * freq_sep / (tuning_efficiency * heating_efficiency); + } + else if (tuning_method == "ElectricalAssistWithBitReshuffle") + { + // Electrical assistance allows for a fraction of the tuning range to be + // covered electrically. This is most pronounced when the tuning range is small, + // such is the case when bit reshuffling is applied + + // Get electrically tunable range + double max_assist = getTechModel()->get("Ring->MaxElectricallyTunableFreq"); + + // Setup calculations + double L = 2 * pi * R; // Optical length + double FSR = c / (n_g * L); // Free spectral range + double freq_sep = FSR / number_rings; // Channel separation + double heating_range = std::max(0.0, freq_sep - max_assist); // The distance needed to bridge using heaters + + // Calculate tuning power, which is really only the power spent on heating since + // distance tuned electrically is pretty much free + tuning_power = number_rings * heating_range / (tuning_efficiency * heating_efficiency); + } + else if (tuning_method == "FullThermal") + { + // If there is no bit reshuffling backend, each ring must tune to an + // absolute channel frequency. Since we can only heat rings (and not cool), + // we can only red-shift (decrease frequency). Thus, a fabrication bias + // must be applied such that under any process and temperature corner, the + // ring resonance remains above channel resonance + // I'll use 3 sigmas of sigma_r_local and sigma_r_systematic, and bias against + // the full temperature range + double fabrication_bias_freq = 3.0 * sqrt(pow(sigma_r_local, 2) + pow(sigma_r_systematic, 2)) + + (T_max - T_min) * tuning_efficiency; + + // The local/systematic variations are 0 on average. Thus, the tuning distance can be calculated as + double tuning_distance = fabrication_bias_freq - (T - T_min) * tuning_efficiency; + + // Tuning power needed is just the number of rings * tuning distance / (tuning and heating efficiencies) + tuning_power = number_rings * tuning_distance / (tuning_efficiency * heating_efficiency); + } + else if (tuning_method == "AthermalWithTrim") + { + // Athermal! + tuning_power = 0; + } + else + { + ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown ring tuning method '" + tuning_method + "'!"); + } + + return tuning_power; + } + + unsigned int OpticalLinkBackendRx::getBitReorderDegree() + { + // Get properties + unsigned int number_rings = getGenProperties()->get("InBits"); + + // Get tech model parameters + double R = getTechModel()->get("Ring->Radius"); + double n_g = getTechModel()->get("Ring->GroupIndex"); + // This can actually be derived if we know thermo-optic coefficient (delta n / delta T) + double sigma_r_local = getTechModel()->get("Ring->LocalVariationSigma"); + + // Get constants + double c = Constants::c; + double pi = Constants::pi; + + // Calculates the degree of bit re-order multiplexing needed for bit-reshuffling backend + // Bit reshuffling tuning is largely unaffected by sigma_r_systematic. However, sigma_r_local + // Can potentially throw each ring to a channel several channels away. This just calculates + // the degree of bit reorder muxing needed to realign bits in the correct order + + // Setup calculations + double L = 2 * pi * R; // Optical length + double FSR = c / (n_g * L); // Free spectral range + double freq_sep = FSR / number_rings; // Channel separation + // Using 4 sigmas as the worst re-ordering case (must double to get both sides) + unsigned int worst_case_channels = (unsigned int)ceil(2.0 * 4.0 * sigma_r_local / freq_sep); + + return worst_case_channels; + } + +} // namespace DSENT + diff --git a/ext/dsent/model/optical/OpticalLinkBackendRx.h b/ext/dsent/model/optical/OpticalLinkBackendRx.h new file mode 100644 index 000000000..19f396664 --- /dev/null +++ b/ext/dsent/model/optical/OpticalLinkBackendRx.h @@ -0,0 +1,39 @@ +#ifndef __DSENT_MODEL_OPTICAL_OPTICALLINKBACKENDRX_H__ +#define __DSENT_MODEL_OPTICAL_OPTICALLINKBACKENDRX_H__ + +#include "util/CommonType.h" +#include "model/ElectricalModel.h" + +namespace DSENT +{ + class OpticalLinkBackendRx : public ElectricalModel + { + // An optical link backend rx contains everything needed for thermal + // tuning of rings, bit-reshuffling (if necessary), and deserialization (if necessary) + public: + OpticalLinkBackendRx(const String& instance_name_, const TechModel* tech_model_); + virtual ~OpticalLinkBackendRx(); + + public: + // Set a list of properties' name needed to construct model + void initParameters(); + // Set a list of properties' name needed to construct model + void initProperties(); + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void propagateTransitionInfo(); + + private: + // Calculate ring tuning power + double getRingTuningPower(); + // Calculate the degree of bit re-order muxing (for the bit-reshuffler) + unsigned int getBitReorderDegree(); + + }; // class OpticalLinkBackendRx +} // namespace DSENT + +#endif // __DSENT_MODEL_OPTICAL_OPTICALLINKBACKENDRX_H__ + diff --git a/ext/dsent/model/optical/OpticalLinkBackendTx.cc b/ext/dsent/model/optical/OpticalLinkBackendTx.cc new file mode 100644 index 000000000..18d86cfe7 --- /dev/null +++ b/ext/dsent/model/optical/OpticalLinkBackendTx.cc @@ -0,0 +1,355 @@ +#include "model/optical/OpticalLinkBackendTx.h" + +#include "util/Constants.h" +#include "model/PortInfo.h" +#include "model/TransitionInfo.h" +#include "model/EventInfo.h" +#include "model/electrical/MuxTreeSerializer.h" +#include "model/electrical/BarrelShifter.h" +#include "model/electrical/Multiplexer.h" +#include <cmath> + +namespace DSENT +{ + // TODO: Kind of don't like the way thermal tuning is written here. Maybe will switch + // to curve fitting the CICC paper, which uses results from a monte-carlo sim + + OpticalLinkBackendTx::OpticalLinkBackendTx(const String& instance_name_, const TechModel* tech_model_) + : ElectricalModel(instance_name_, tech_model_) + { + initParameters(); + initProperties(); + } + + OpticalLinkBackendTx::~OpticalLinkBackendTx() + {} + + void OpticalLinkBackendTx::initParameters() + { + addParameterName("InBits"); + addParameterName("CoreDataRate"); + addParameterName("LinkDataRate"); + addParameterName("RingTuningMethod"); + addParameterName("BitDuplicate"); + return; + } + + void OpticalLinkBackendTx::initProperties() + { + return; + } + + void OpticalLinkBackendTx::constructModel() + { + unsigned int in_bits = getParameter("InBits"); + double core_data_rate = getParameter("CoreDataRate"); + double link_data_rate = getParameter("LinkDataRate"); + const String& tuning_method = getParameter("RingTuningMethod");; + bool bit_duplicate = getParameter("BitDuplicate"); + + // Calculate serialization ratio + unsigned int serialization_ratio = (unsigned int) floor(link_data_rate / core_data_rate); + ASSERT(serialization_ratio == link_data_rate / core_data_rate, + "[Error] " + getInstanceName() + " -> Cannot have non-integer serialization ratios " + + "(" + (String) (core_data_rate / link_data_rate) + ")!"); + + // Calculate output width + ASSERT(floor((double) in_bits / serialization_ratio) == (double) in_bits / serialization_ratio, + "[Error] " + getInstanceName() + " -> Input width (" + (String) in_bits + ") " + + "must be a multiple of the serialization ratio (" + (String) serialization_ratio + ")!"); + unsigned int out_bits = in_bits / serialization_ratio; + + getGenProperties()->set("SerializationRatio", serialization_ratio); + getGenProperties()->set("OutBits", out_bits); + + // Create ports + createInputPort("In", makeNetIndex(0, in_bits-1)); + createInputPort("LinkCK"); + createOutputPort("Out", makeNetIndex(0, out_bits-1)); + + //Create energy, power, and area results + createElectricalResults(); + // Create ring heating power cost + addNddPowerResult(new AtomicResult("RingTuning")); + // Create process bits event + createElectricalEventResult("ProcessBits"); + getEventInfo("ProcessBits")->setTransitionInfo("LinkCK", TransitionInfo(0.0, (double) serialization_ratio / 2.0, 0.0)); + // Set conditions during idle state + getEventInfo("Idle")->setStaticTransitionInfos(); + getEventInfo("Idle")->setTransitionInfo("LinkCK", TransitionInfo(0.0, (double) serialization_ratio / 2.0, 0.0)); + + // Create serializer + const String& serializer_name = "Serializer"; + MuxTreeSerializer* serializer = new MuxTreeSerializer(serializer_name, getTechModel()); + serializer->setParameter("InBits", in_bits); + serializer->setParameter("InDataRate", core_data_rate); + serializer->setParameter("OutDataRate", link_data_rate); + serializer->setParameter("BitDuplicate", bit_duplicate); + serializer->construct(); + + addSubInstances(serializer, 1.0); + addElectricalSubResults(serializer, 1.0); + getEventResult("ProcessBits")->addSubResult(serializer->getEventResult("Serialize"), serializer_name, 1.0); + + if ((tuning_method == "ThermalWithBitReshuffle") || (tuning_method == "ElectricalAssistWithBitReshuffle")) + { + // If a bit reshuffling backend is present, create the reshuffling backend + unsigned int reorder_degree = getBitReorderDegree(); + + // Create intermediate nets + createNet("SerializerIn", makeNetIndex(0, in_bits-1)); + createNet("ReorderIn", makeNetIndex(0, out_bits+reorder_degree-1)); + assign("ReorderIn", makeNetIndex(out_bits, out_bits+reorder_degree-1), "ReorderIn", makeNetIndex(0, reorder_degree-1)); + + // Create barrelshifter + unsigned int shift_index_min = (unsigned int)ceil(log2(serialization_ratio)); + unsigned int shift_index_max = std::max(shift_index_min, (unsigned int) ceil(log2(in_bits)) - 1); + + // Remember some things + getGenProperties()->set("ReorderDegree", reorder_degree); + getGenProperties()->set("ShiftIndexMin", shift_index_min); + getGenProperties()->set("ShiftIndexMax", shift_index_max); + + const String& barrel_shift_name = "BarrelShifter"; + BarrelShifter* barrel_shift = new BarrelShifter(barrel_shift_name, getTechModel()); + barrel_shift->setParameter("NumberBits", in_bits); + barrel_shift->setParameter("ShiftIndexMax", shift_index_max); + barrel_shift->setParameter("ShiftIndexMin", shift_index_min); + barrel_shift->setParameter("BitDuplicate", bit_duplicate); + barrel_shift->construct(); + + // Create bit reorder muxes + const String& reorder_mux_name = "ReorderMux"; + Multiplexer* reorder_mux = new Multiplexer(reorder_mux_name, getTechModel()); + reorder_mux->setParameter("NumberBits", out_bits); + reorder_mux->setParameter("NumberInputs", reorder_degree); + reorder_mux->setParameter("BitDuplicate", bit_duplicate); + reorder_mux->construct(); + + // Connect barrelshifter + // TODO: Connect barrelshift shifts! + portConnect(barrel_shift, "In", "In"); + portConnect(barrel_shift, "Out", "SerializerIn"); + + // Connect serializer + portConnect(serializer, "In", "SerializerIn"); + portConnect(serializer, "Out", "ReorderIn", makeNetIndex(0, out_bits-1)); + portConnect(serializer, "OutCK", "LinkCK"); + + // Connect bit reorder muxes + // TODO: Connect re-order multiplex select signals! + for (unsigned int i = 0; i < reorder_degree; i++) + portConnect(reorder_mux, "In" + (String) i, "ReorderIn", makeNetIndex(i, i+out_bits-1)); + portConnect(reorder_mux, "Out", "Out"); + + addSubInstances(barrel_shift, 1.0); + addSubInstances(reorder_mux, 1.0); + addElectricalSubResults(barrel_shift, 1.0); + addElectricalSubResults(reorder_mux, 1.0); + getEventResult("ProcessBits")->addSubResult(barrel_shift->getEventResult("BarrelShift"), barrel_shift_name, 1.0); + getEventResult("ProcessBits")->addSubResult(reorder_mux->getEventResult("Mux"), reorder_mux_name, 1.0); // This happens multiple times + } + else if ((tuning_method == "FullThermal") || (tuning_method == "AthermalWithTrim")) + { + // If no bit reshuffling backend is present, then just connect serializer up + portConnect(serializer, "In", "In"); + portConnect(serializer, "Out", "Out"); + portConnect(serializer, "OutCK", "LinkCK"); + } + else + { + ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown ring tuning method '" + tuning_method + "'!"); + } + + return; + } + + void OpticalLinkBackendTx::updateModel() + { + // Update everyone + Model::updateModel(); + // Update ring tuning power + getNddPowerResult("RingTuning")->setValue(getRingTuningPower()); + return; + } + + void OpticalLinkBackendTx::propagateTransitionInfo() + { + // Get parameters + const String& tuning_method = getParameter("RingTuningMethod"); + + // Update the serializer + if ((tuning_method == "ThermalWithBitReshuffle") || (tuning_method == "ElectricalAssistWithBitReshuffle")) + { + // Get generated properties + unsigned int reorder_degree = getGenProperties()->get("ReorderDegree").toUInt(); + unsigned int shift_index_min = getGenProperties()->get("ShiftIndexMin").toUInt(); + unsigned int shift_index_max = getGenProperties()->get("ShiftIndexMax").toUInt(); + + // Update barrel shifter + const String& barrel_shift_name = "BarrelShifter"; + ElectricalModel* barrel_shift = (ElectricalModel*) getSubInstance(barrel_shift_name); + propagatePortTransitionInfo(barrel_shift, "In", "In"); + // Set shift transitions to be very low (since it is affected by slow temperature time constants) + for (unsigned int i = shift_index_min; i <= shift_index_max; ++i) + barrel_shift->getInputPort("Shift" + (String) i)->setTransitionInfo(TransitionInfo(0.499, 0.001, 0.499)); + barrel_shift->use(); + + // Set serializer transition info + ElectricalModel* serializer = (ElectricalModel*) getSubInstance("Serializer"); + propagatePortTransitionInfo(serializer, "In", barrel_shift, "Out"); + propagatePortTransitionInfo(serializer, "OutCK", "LinkCK"); + serializer->use(); + + // Reorder mux shift select bits + unsigned int reorder_sel_bits = (unsigned int)ceil(log2(reorder_degree)); + + // Reorder mux probabilities + const String& reorder_mux_name = "ReorderMux"; + ElectricalModel* reorder_mux = (ElectricalModel*) getSubInstance(reorder_mux_name); + for (unsigned int i = 0; i < reorder_degree; ++i) + propagatePortTransitionInfo(reorder_mux, "In" + (String) i, serializer, "Out"); + // Set select transitions to be 0, since these are statically configured + for (unsigned int i = 0; i < reorder_sel_bits; ++i) + reorder_mux->getInputPort("Sel" + (String) i)->setTransitionInfo(TransitionInfo(0.5, 0.0, 0.5)); + reorder_mux->use(); + + // Set output transition info + propagatePortTransitionInfo("Out", reorder_mux, "Out"); + } + else if ((tuning_method == "FullThermal") || (tuning_method == "AthermalWithTrim")) + { + // Set serializer transition info + ElectricalModel* serializer = (ElectricalModel*) getSubInstance("Serializer"); + propagatePortTransitionInfo(serializer, "In", "In"); + propagatePortTransitionInfo(serializer, "OutCK", "LinkCK"); + serializer->use(); + + // Set output transition info + propagatePortTransitionInfo("Out", serializer, "Out"); + } + + return; + } + + double OpticalLinkBackendTx::getRingTuningPower() + { + // Get properties + const String& tuning_method = getParameter("RingTuningMethod");; + unsigned int number_rings = getGenProperties()->get("OutBits"); + + // Get tech model parameters + double R = getTechModel()->get("Ring->Radius"); + double n_g = getTechModel()->get("Ring->GroupIndex"); + double heating_efficiency = getTechModel()->get("Ring->HeatingEfficiency"); + // This can actually be derived if we know thermo-optic coefficient (delta n / delta T) + double tuning_efficiency = getTechModel()->get("Ring->TuningEfficiency"); + double sigma_r_local = getTechModel()->get("Ring->LocalVariationSigma"); + double sigma_r_systematic = getTechModel()->get("Ring->SystematicVariationSigma"); + double T_max = getTechModel()->get("Ring->TemperatureMax"); + double T_min = getTechModel()->get("Ring->TemperatureMin"); + double T = getTechModel()->get("Temperature"); + + // Get constants + double c = Constants::c; + double pi = Constants::pi; + + double tuning_power = 0.0; + + if (tuning_method == "ThermalWithBitReshuffle") + { + // When an electrical backend is present, rings only have to tune to the nearest channel + // This can be approximated as each ring tuning to something exactly 1 channel away + + // Setup calculations + double L = 2 * pi * R; // Optical length + double FSR = c / (n_g * L); // Free spectral range + double freq_sep = FSR / number_rings; // Channel separation + + // Calculate tuning power + tuning_power = number_rings * freq_sep / (tuning_efficiency * heating_efficiency); + } + else if (tuning_method == "ElectricalAssistWithBitReshuffle") + { + // Electrical assistance allows for a fraction of the tuning range to be + // covered electrically. This is most pronounced when the tuning range is small, + // such is the case when bit reshuffling is applied. The electrically + // assisted part of it pretty much comes for free... + + // Get electrically tunable range + double max_assist = getTechModel()->get("Ring->MaxElectricallyTunableFreq"); + + // Setup calculations + double L = 2 * pi * R; // Optical length + double FSR = c / (n_g * L); // Free spectral range + double freq_sep = FSR / number_rings; // Channel separation + double heating_range = std::max(0.0, freq_sep - max_assist); // The distance needed to bridge using heaters + + // Calculate tuning power, which is really only the power spent on heating since + // distance tuned electrically is pretty much free + tuning_power = number_rings * heating_range / (tuning_efficiency * heating_efficiency); + } + else if (tuning_method == "FullThermal") + { + // If there is no bit reshuffling backend, each ring must tune to an + // absolute channel frequency. Since we can only heat rings (and not cool), + // we can only red-shift (decrease frequency). Thus, a fabrication bias + // must be applied such that under any process and temperature corner, the + // ring resonance remains above channel resonance + // I'll use 3 sigmas of sigma_r_local and sigma_r_systematic, and bias against + // the full temperature range + double fabrication_bias_freq = 3.0 * sqrt(pow(sigma_r_local, 2) + pow(sigma_r_systematic, 2)) + + (T_max - T_min) * tuning_efficiency; + + // The local/systematic variations are 0 on average. Thus, the tuning distance can be calculated as + double tuning_distance = fabrication_bias_freq - (T - T_min) * tuning_efficiency; + + // Tuning power needed is just the number of rings * tuning distance / (tuning and heating efficiencies) + tuning_power = number_rings * tuning_distance / (tuning_efficiency * heating_efficiency); + } + else if (tuning_method == "AthermalWithTrim") + { + // Athermal! Each ring's process variations are trimmed! Everything is free! + // Basically an ideal scenario + tuning_power = 0; + } + else + { + ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown ring tuning method '" + tuning_method + "'!"); + } + + return tuning_power; + } + + unsigned int OpticalLinkBackendTx::getBitReorderDegree() + { + // Get properties + unsigned int number_rings = getGenProperties()->get("OutBits"); + + // Get tech model parameters + double R = getTechModel()->get("Ring->Radius"); + double n_g = getTechModel()->get("Ring->GroupIndex"); + // This can actually be derived if we know thermo-optic coefficient (delta n / delta T) + double sigma_r_local = getTechModel()->get("Ring->LocalVariationSigma"); + + // Get constants + double c = Constants::c; + double pi = Constants::pi; + + // Calculates the degree of bit re-order multiplexing needed for bit-reshuffling backend + // Bit reshuffling tuning is largely unaffected by sigma_r_systematic. However, sigma_r_local + // Can potentially throw each ring to a channel several channels away. This just calculates + // the degree of bit reorder muxing needed to realign bits in the correct order + + // Setup calculations + double L = 2 * pi * R; // Optical length + double FSR = c / (n_g * L); // Free spectral range + double freq_sep = FSR / number_rings; // Channel separation + // Using 4 sigmas as the worst re-ordering case (must double to get both sides) + unsigned int worst_case_channels = (unsigned int)ceil(2.0 * 4.0 * sigma_r_local / freq_sep); + + return worst_case_channels; + } + +} // namespace DSENT + diff --git a/ext/dsent/model/optical/OpticalLinkBackendTx.h b/ext/dsent/model/optical/OpticalLinkBackendTx.h new file mode 100644 index 000000000..a3e596403 --- /dev/null +++ b/ext/dsent/model/optical/OpticalLinkBackendTx.h @@ -0,0 +1,39 @@ +#ifndef __DSENT_MODEL_OPTICAL_OPTICALLINKBACKENDTX_H__ +#define __DSENT_MODEL_OPTICAL_OPTICALLINKBACKENDTX_H__ + +#include "util/CommonType.h" +#include "model/ElectricalModel.h" + +namespace DSENT +{ + class OpticalLinkBackendTx : public ElectricalModel + { + // An optical link backend tx contains everything needed for thermal + // tuning of rings, bit-reshuffling (if necessary), and serialization (if necessary) + public: + OpticalLinkBackendTx(const String& instance_name_, const TechModel* tech_model_); + virtual ~OpticalLinkBackendTx(); + + public: + // Set a list of properties' name needed to construct model + void initParameters(); + // Set a list of properties' name needed to construct model + void initProperties(); + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void propagateTransitionInfo(); + + private: + // Calculate ring tuning power + double getRingTuningPower(); + // Calculate the degree of bit re-order muxing (for the bit-reshuffler) + unsigned int getBitReorderDegree(); + + }; // class OpticalLinkBackendTx +} // namespace DSENT + +#endif // __DSENT_MODEL_OPTICAL_OPTICALLINKBACKENDTX_H__ + diff --git a/ext/dsent/model/optical/OpticalTestModel.cc b/ext/dsent/model/optical/OpticalTestModel.cc new file mode 100644 index 000000000..c821c4841 --- /dev/null +++ b/ext/dsent/model/optical/OpticalTestModel.cc @@ -0,0 +1,121 @@ +#include "model/optical/OpticalTestModel.h" +#include "model/optical_graph/OpticalGraph.h" +#include "model/optical_graph/OpticalWaveguide.h" +#include "model/optical/RingModulator.h" +#include "model/optical/RingFilter.h" +#include "model/optical/RingDetector.h" +#include "model/optical/LaserSource.h" + +namespace DSENT +{ + OpticalTestModel::OpticalTestModel(const String& instance_name_, const TechModel* tech_model_) + : OpticalModel(instance_name_, tech_model_) + { + initParameters(); + initProperties(); + } + + OpticalTestModel::~OpticalTestModel() + {} + + void OpticalTestModel::initParameters() + { + return; + } + + void OpticalTestModel::initProperties() + { + return; + } + + void OpticalTestModel::constructModel() + { + unsigned int wavelengths = 64; + unsigned int number_readers = 1; + + createWaveguide("LaserToMod", makeWavelengthGroup(0, wavelengths-1)); + + // Create laser + LaserSource* laser = new LaserSource("Laser", getTechModel()); + laser->setParameter("OutStart", 0); + laser->setParameter("OutEnd", wavelengths-1); + laser->construct(); + + // Create modulator + RingModulator* modulator = new RingModulator("Modulator", getTechModel()); + modulator->setParameter("InStart", 0); + modulator->setParameter("InEnd", wavelengths-1); + modulator->setParameter("ModStart", 0); + modulator->setParameter("ModEnd", wavelengths-1); + modulator->construct(); + + for (unsigned int i = 0; i <= number_readers; ++i) + { + String n = (String) i; + createWaveguide("WaveguideDet-" + n, makeWavelengthGroup(0, wavelengths-1)); + } + + // Create a SWMR Configuration + for (unsigned int i = 0; i < number_readers; ++i) + { + String n = (String) i; + + // Create resonant ring detector + RingDetector* detector = new RingDetector("Detector-" + n, getTechModel()); + detector->setParameter("InStart", 0); + detector->setParameter("InEnd", wavelengths-1); + detector->setParameter("DetStart", 0); + detector->setParameter("DetEnd", wavelengths-1); + detector->setParameter("DropAll", "FALSE"); + detector->setParameter("SenseAmp", "TRUE"); + detector->construct(); + + opticalPortConnect(detector, "In", "WaveguideDet-" + n); + opticalPortConnect(detector, "Out", "WaveguideDet-" + (String) (i + 1)); + + addSubInstances(detector, 1.0); + } + + opticalPortConnect(laser, "Out", "LaserToMod"); + opticalPortConnect(modulator, "In", "LaserToMod"); + opticalPortConnect(modulator, "Out", "WaveguideDet-0"); + + addSubInstances(laser, 1.0); + addSubInstances(modulator, 1.0); + } + + void OpticalTestModel::updateModel() + { + double data_rate = 8e9; + double extinction_ratio = 5; + double insertion_loss = 3; + + Model* laser = getSubInstance("Laser"); + laser->update(); + + getWaveguide("LaserToMod")->setLoss(10); + + Model* modulator = getSubInstance("Modulator"); + modulator->setProperty("ExtinctionRatio", extinction_ratio); + modulator->setProperty("InsertionLoss", insertion_loss); + modulator->setProperty("DataRate", data_rate); + modulator->setProperty("P(In)", 0.5); + modulator->setProperty("Act(In)", 1.0); + modulator->update(); + + unsigned int number_readers = 1; + for (unsigned int i = 0; i < number_readers; ++i) + { + Model* detector = getSubInstance("Detector-" + (String) i); + detector->setProperty("ExtinctionRatio", extinction_ratio); + detector->setProperty("DataRate", data_rate); + detector->setProperty("P(In)", 0.5); + detector->setProperty("Act(In)", 1.0); + detector->update(); + } + + + } + +} // namespace DSENT + diff --git a/ext/dsent/model/optical/OpticalTestModel.h b/ext/dsent/model/optical/OpticalTestModel.h new file mode 100644 index 000000000..06a80e955 --- /dev/null +++ b/ext/dsent/model/optical/OpticalTestModel.h @@ -0,0 +1,30 @@ +#ifndef __DSENT_MODEL_OPTICAL_OPTICALTESTMODEL_H__ +#define __DSENT_MODEL_OPTICAL_OPTICALTESTMODEL_H__ + +#include "util/CommonType.h" +#include "model/OpticalModel.h" + +namespace DSENT +{ + class OpticalTestModel : public OpticalModel + { + public: + OpticalTestModel(const String& instance_name_, const TechModel* tech_model_); + virtual ~OpticalTestModel(); + + public: + // Set a list of properties' name needed to construct model + void initParameters(); + // Set a list of properties' name needed to construct model + void initProperties(); + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + + }; // class OpticalTestModel +} // namespace DSENT + +#endif // __DSENT_MODEL_OPTICAL_RINGLASERSOURCE_H__ + diff --git a/ext/dsent/model/optical/RingDetector.cc b/ext/dsent/model/optical/RingDetector.cc new file mode 100644 index 000000000..4baf2f68f --- /dev/null +++ b/ext/dsent/model/optical/RingDetector.cc @@ -0,0 +1,338 @@ +#include "model/optical/RingDetector.h" + +#include <cmath> + +#include "util/Constants.h" +#include "model/PortInfo.h" +#include "model/TransitionInfo.h" +#include "model/EventInfo.h" +#include "model/std_cells/StdCell.h" +#include "model/std_cells/StdCellLib.h" +#include "model/optical_graph/OpticalWaveguide.h" +#include "model/optical_graph/OpticalDetector.h" +#include "model/optical_graph/OpticalFilter.h" +#include "model/timing_graph/ElectricalDriver.h" +#include "model/timing_graph/ElectricalNet.h" + +namespace DSENT +{ + // TODOs for this model + // Add the other receiver topologies from [Georgas, CICC 2011] + // Split integ_time_ratio = SA integ time ratio + // Right now perfect clock gating is assumed...may not be what we want + + // Constants + const String RingDetector::INTEGRATINGSENSEAMP = "INTSA"; + + RingDetector::RingDetector(const String& instance_name_, const TechModel* tech_model_) + : OpticalModel(instance_name_, tech_model_), OpticalReceiver() + { + initParameters(); + initProperties(); + } + + RingDetector::~RingDetector() + {} + + void RingDetector::initParameters() + { + addParameterName("DataRate"); + addParameterName("InStart"); + addParameterName("InEnd"); + addParameterName("DetStart"); + addParameterName("DetEnd"); + addParameterName("DropAll"); + addParameterName("Topology"); + return; + } + + void RingDetector::initProperties() + { + return; + } + + void RingDetector::constructModel() + { + // Get parameters + WavelengthGroup in_wavelengths = makeWavelengthGroup(getParameter("InStart"), getParameter("InEnd")); + WavelengthGroup det_wavelengths = makeWavelengthGroup(getParameter("DetStart"), getParameter("DetEnd")); + int number_wavelengths = det_wavelengths.second - det_wavelengths.first + 1; + bool drop_all = getParameter("DropAll"); + const String& topology = getParameter("Topology"); + + // Set some generated properties + getGenProperties()->set("NumberWavelengths", number_wavelengths); + + // Create device area result + addAreaResult(new AtomicResult("Photonic")); + // Create electrical results + createElectricalAtomicResults(); + if (topology == INTEGRATINGSENSEAMP) addEventResult(new AtomicResult("Receive")); + else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown receiver topology (" + topology + ")!"); + + // Create optical ports + createOpticalInputPort( "In", in_wavelengths); + createOpticalOutputPort( "Out", in_wavelengths); + // Create the filter and modulator + createFilter( "RingFilter", in_wavelengths, drop_all, det_wavelengths); + createDetector( "RingDetector", det_wavelengths, this); + OpticalFilter* ring_filter = getFilter("RingFilter"); + OpticalDetector* ring_detector = getDetector("RingDetector"); + // Connect the filter and modulator + getWaveguide("In")->addDownstreamNode(ring_filter); + ring_filter->addDownstreamNode(getWaveguide("Out")); + ring_filter->setDropPort(ring_detector); + + // Create electrical ports + createOutputPort("Out", makeNetIndex(0, number_wavelengths-1)); + // Create net + createNet("OutVFO"); + // Create output driver + createDriver("OutDriver", false); + // Connect driver + getDriver("OutDriver")->addDownstreamNode(getNet("OutVFO")); + // Connect output + assignVirtualFanout("Out", "OutVFO"); + + // Precompute some technology values + precomputeTech(); + + return; + } + + void RingDetector::updateModel() + { + // Get some generated properties + unsigned int number_wavelengths = getGenProperties()->get("NumberWavelengths"); + + // Get tech model numbers + double ring_area = getTechModel()->get("Ring->Area"); + double thru_loss = getTechModel()->get("Ring->ThroughLoss"); + double drop_loss = getTechModel()->get("Ring->DropLoss"); + double pd_loss = getTechModel()->get("Photodetector->Loss"); + double pd_responsivity = getTechModel()->get("Photodetector->Responsivity"); + + // Design the receiver + designReceiver(); + + // Update losses + // Connect the filter and modulator + OpticalFilter* ring_filter = getFilter("RingFilter"); + OpticalDetector* ring_detector = getDetector("RingDetector"); + ring_filter->setLoss(thru_loss * number_wavelengths); + ring_filter->setDropLoss(drop_loss + thru_loss * number_wavelengths); + ring_detector->setLoss(pd_loss); + ring_detector->setResponsivity(pd_responsivity); + // Update device area + getAreaResult("Photonic")->setValue(ring_area * (number_wavelengths)); + + return; + } + + void RingDetector::useModel() + { + // Get parameters + const String& topology = getParameter("Topology"); + + // Get some generated properties + unsigned int number_wavelengths = getGenProperties()->get("NumberWavelengths"); + + // Get optical input transition info + const TransitionInfo& in_trans = getOpticalInputPort("In")->getTransitionInfo(); + + // Get tech models + double vdd = getTechModel()->get("Vdd"); + // Get caps + double unit_gate_cap = getTechModel()->get("Gate->MinWidth").toDouble() * getTechModel()->get("Gate->CapPerWidth").toDouble(); + double unit_drain_cap = getTechModel()->get("Gate->MinWidth").toDouble() * getTechModel()->get("Drain->CapPerWidth").toDouble(); + double inv_x1_gate_cap = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->A"); + double inv_x1_drain_cap = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->Y"); + + // Construct a simple sense-amp model + if(topology == INTEGRATINGSENSEAMP) + { + // Use ratios from the receiver published in [Georgas, ESSCIRC 2011] + // Note: + // The numbers in the paper (43fJ/b, 50 fJ/b in the cited work) is done with the clock buffer (there are 4 receivers), + // capacitive DAC, and extra output flops used in the physical layout, as the compared receiver is extremely conservative + // We simplified this model to not have the capacitive DAC, the clock buffer (since this is an individual receiver), or + // the extra output flops (since receiver structure is already a posedge flop functionally). + // Look for an upcoming paper [Georgas, JSSC 2012] (when it is published) for the power breakdown pie-chart for the receiver. + // This model only models the latch (sampler) and the dynamic to static (RS latch) part of the design, which is all you really + // need in the receiver. + + // Gate caps + double c_gate_sampler = unit_gate_cap * (4 * 2.0 + 2 * 1.0 + 2 * 3.0 + 2 * 5.0) + unit_gate_cap * (2 * 6.0 + 2 * 1.0) + inv_x1_gate_cap; + double c_gate_rslatch = unit_gate_cap * (4 * 1.0) + inv_x1_gate_cap; + // Drain caps + double c_drain_sampler = unit_drain_cap * (2 * 2.0 + 2 * 1.0 + 3 * 5.0 + 1 * 3.0) + inv_x1_drain_cap; + double c_drain_rslatch = unit_drain_cap * (2 * 6.0) + inv_x1_drain_cap; + // Sum up cap switched for the sampler + double c_sampler = c_gate_sampler + c_drain_sampler; + double c_rslatch = c_gate_rslatch + c_drain_rslatch; + // Average cap switched + // Sampler is differential, one side will always switch (R or S in the latch) regardless of probability + double avg_cap = c_sampler + c_rslatch * in_trans.getProbability0() * in_trans.getProbability1(); + + // Get parameters corresponding to a unit-inverter + double unit_leak_0 = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Leakage->!A"); + double unit_leak_1 = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Leakage->A"); + + // Approximate leakage (curve fit with design) + double total_leakage = 0.5 * (unit_leak_0 + unit_leak_1) * 7.43; + + // Create results + getEventResult("Receive")->setValue(vdd * vdd * avg_cap * number_wavelengths); + getNddPowerResult("Leakage")->setValue(total_leakage * number_wavelengths); + + } + else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown receiver topology (" + topology + ")!"); + + return; + } + + void RingDetector::propagateTransitionInfo() + { + // Propagate probabilities from optical input to electrical output port + getOutputPort("Out")->setTransitionInfo(getOpticalInputPort("In")->getTransitionInfo()); + + return; + } + + void RingDetector::precomputeTech() + { + // Get parameters + const double data_rate = getParameter("DataRate"); + const String& topology = getParameter("Topology"); + + // Get tech model numbers + double pd_cap = getTechModel()->get("Photodetector->Cap"); + double parasitic_cap = getTechModel()->get("Photodetector->ParasiticCap"); + double apd = getTechModel()->get("Photodetector->AvalancheGain"); + double vdd = getTechModel()->get("Vdd"); + + // Constants shortcuts + double pi = Constants::pi; + double k = Constants::k; + double q = Constants::q; + double T = getTechModel()->get("Temperature"); + + if(topology == INTEGRATINGSENSEAMP) + { + // Get more tech parameters + double integ_time_ratio = getTechModel()->get("Receiver->Int->IntegrationTimeRatio"); + double BER = getTechModel()->get("SenseAmp->BER"); + double CMRR = getTechModel()->get("SenseAmp->CMRR"); + double offset_comp_bits = getTechModel()->get("SenseAmp->OffsetCompensationBits"); + double offset = getTechModel()->get("SenseAmp->OffsetRatio").toDouble() * vdd; + double supply_noise_rand = getTechModel()->get("SenseAmp->SupplyNoiseRandRatio").toDouble() * vdd; + double supply_noise_det = getTechModel()->get("SenseAmp->SupplyNoiseDetRatio").toDouble() * vdd; + double noise_margin = getTechModel()->get("SenseAmp->NoiseMargin"); + double jitter_ratio = getTechModel()->get("SenseAmp->JitterRatio"); + + // Approximate tao using FO4 + double unit_drain_cap = getTechModel()->get("Gate->MinWidth").toDouble() * getTechModel()->get("Drain->CapPerWidth").toDouble(); + double c_g = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->A"); + double c_d = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->Y"); + double r_o = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->DriveRes->Y"); + // Calculate sense amp tau from sense amp output loading + double tau = r_o * (c_g + c_d); + // Set output inverter drive strength + getDriver("OutDriver")->setOutputRes(r_o); + + // Calculate sense amp input cap based on schematic + double sense_amp_cap_in = unit_drain_cap * (2.0 + 3.0 + 5.0 + 1.0); + + // Residual offset + double v_residual = 3 * offset / pow(2, offset_comp_bits); + // Noise + double v_noise = supply_noise_rand * supply_noise_rand / (CMRR * CMRR); + // Sense amp voltage build-up minimum + double v_sense = vdd * exp(-(1 - integ_time_ratio) / (data_rate * tau)) + noise_margin + v_residual + supply_noise_det / CMRR; + // Sigmas corresponding to BER + double sigma = calcInvNormCdf(BER); + + //K_int is the time the bit is valid for evaluation + + // Total input cap load + double input_node_cap = sense_amp_cap_in + pd_cap + parasitic_cap; + double z_int = integ_time_ratio / (data_rate * input_node_cap); //should use K_int + + // Store precalculated values + m_quad_a_ = 1 - (sigma * sigma * jitter_ratio * jitter_ratio); + m_quad_b1_ = - 2 * pi / 2 * sigma * sigma * q * 0.7 * data_rate; + m_quad_b2_ = -2 * v_sense / (z_int * apd); + m_quad_c_ = 1 / (z_int * z_int) * (v_sense * v_sense - sigma * sigma * (k * T / input_node_cap + v_noise)); + } + else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown receiver topology (" + topology + ")!"); + + return; + } + + void RingDetector::designReceiver() + { + // Get some generated properties + unsigned int number_wavelengths = getGenProperties()->get("NumberWavelengths"); + + // Get relevant properties/parameters + const String& topology = getParameter("Topology"); + + // Construct a simple sense-amp model + if(topology == INTEGRATINGSENSEAMP) + { + // No really good way to estimate the area...can assume each receiver is the size of 40 inverters, which is + // about the right size for just the sense amp in the layout + double unit_area_active = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Area->Active"); + double unit_area_metal1 = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Area->Metal1Wire"); + getAreaResult("Active")->setValue(unit_area_active * 40 * number_wavelengths); + getAreaResult("Metal1Wire")->setValue(unit_area_metal1 * 40 * number_wavelengths); + } + else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown receiver topology (" + topology + ")!"); + + return; + } + + double RingDetector::getSensitivity(double ER_dB_) const + { + // Get parameters + const String& topology = getParameter("Topology"); + // Turn extinction ratio into a ratio from dB scale + double ER = pow(10, ER_dB_ / 10); + + // Initialize sensitivity + double sensitivity = 1e99; + // Construct a simple sense-amp model + if(topology == INTEGRATINGSENSEAMP) + { + // Scale photodetector shot noise using ER, add rest of noise source + double b = m_quad_b1_ * (1 + ER) / (2 * (ER - 1)) + m_quad_b2_; + + // Find sensitivity (-b + sqrt(b^2-4ac)) / 2a + sensitivity = ((-b + sqrt(b * b - 4 * m_quad_a_ * m_quad_c_)) / (2 * m_quad_a_)); + } + else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown receiver topology (" + topology + ")!"); + + return sensitivity; + } + + double RingDetector::calcInvNormCdf(double num_) + { + // 53 bit precision for double FP + unsigned int num_iterations = 20; + // Upperbound the step + double step = 20; + double out = step; + // Iteratively guess and check calculation + for (unsigned int i = 0; i < num_iterations; ++i) + { + double current = 0.5 * erfc(out / sqrt(2)); + if (current > num_) out += step; + else out -= step; + step = step * 0.5; + } + + return out; + } + +} // namespace DSENT + diff --git a/ext/dsent/model/optical/RingDetector.h b/ext/dsent/model/optical/RingDetector.h new file mode 100644 index 000000000..e18b2fe75 --- /dev/null +++ b/ext/dsent/model/optical/RingDetector.h @@ -0,0 +1,54 @@ +#ifndef __DSENT_MODEL_OPTICAL_RINGDETECTOR_H__ +#define __DSENT_MODEL_OPTICAL_RINGDETECTOR_H__ + +#include "util/CommonType.h" +#include "model/OpticalModel.h" +#include "model/optical_graph/OpticalReceiver.h" + +namespace DSENT +{ + class RingDetector : public OpticalModel, public OpticalReceiver + { + public: + // Receiver topolgy strings + static const String INTEGRATINGSENSEAMP; + + public: + RingDetector(const String& instance_name_, const TechModel* tech_model_); + virtual ~RingDetector(); + + public: + // Set a list of properties' name needed to construct model + void initParameters(); + // Set a list of properties' name needed to construct model + void initProperties(); + // Returns the sensitivity of the receiver given an extinction ratio + double getSensitivity(double ER_dB_) const; + + private: + // Precompute values based on tech parameters + void precomputeTech(); + // Design the receiver helper function + void designReceiver(); + // Calculates inverse normal cdf + double calcInvNormCdf(double num_); + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void useModel(); + virtual void propagateTransitionInfo(); + + private: + // Precomputed numbers + double m_quad_a_; + double m_quad_b1_; + double m_quad_b2_; + double m_quad_c_; + + }; // class RingDetector +} // namespace DSENT + +#endif // __DSENT_MODEL_OPTICAL_RINGDETECTOR_H__ + diff --git a/ext/dsent/model/optical/RingFilter.cc b/ext/dsent/model/optical/RingFilter.cc new file mode 100644 index 000000000..5f0bd5b40 --- /dev/null +++ b/ext/dsent/model/optical/RingFilter.cc @@ -0,0 +1,77 @@ +#include "model/optical/RingFilter.h" + +#include "model/optical_graph/OpticalWaveguide.h" +#include "model/optical_graph/OpticalFilter.h" + +namespace DSENT +{ + RingFilter::RingFilter(const String& instance_name_, const TechModel* tech_model_) + : OpticalModel(instance_name_, tech_model_) + { + initParameters(); + initProperties(); + } + + RingFilter::~RingFilter() + {} + + void RingFilter::initParameters() + { + addParameterName("InStart"); + addParameterName("InEnd"); + addParameterName("DropStart"); + addParameterName("DropEnd"); + addParameterName("DropAll", "TRUE"); + return; + } + + void RingFilter::initProperties() + { + return; + } + + void RingFilter::constructModel() + { + //TODO: Add tuning energy/ndd-power costs? + + // Create Area result + Result* area_result = new AtomicResult("Photonic"); + addAreaResult(area_result); + + // Get parameters + WavelengthGroup in_wavelengths = makeWavelengthGroup(getParameter("InStart"), getParameter("InEnd")); + WavelengthGroup drop_wavelengths = makeWavelengthGroup(getParameter("DropStart"), getParameter("DropEnd")); + bool drop_all = getParameter("DropAll"); + + // Create optical ports + createOpticalInputPort( "In", in_wavelengths); + createOpticalOutputPort( "Drop", drop_wavelengths); + createOpticalOutputPort( "Out", in_wavelengths); + // Create the filter + createFilter( "RingFilter", in_wavelengths, drop_all, drop_wavelengths); + OpticalFilter* ring_filter = getFilter("RingFilter"); + // Connect the filter + getWaveguide("In")->addDownstreamNode(ring_filter); + ring_filter->addDownstreamNode(getWaveguide("Out")); + ring_filter->setDropPort(getWaveguide("Drop")); + } + + void RingFilter::updateModel() + { + //TODO: Get numbers from tech model; + double ring_area = 200e-12; + double thru_loss = 1e-4; + double drop_loss = 1.0; + // Get parameters + WavelengthGroup drop_wavelengths = makeWavelengthGroup(getParameter("DropStart"), getParameter("DropEnd")); + int number_wavelengths = drop_wavelengths.second - drop_wavelengths.first + 1; + // Update losses + OpticalFilter* ring_filter = getFilter("RingFilter"); + ring_filter->setLoss(thru_loss * number_wavelengths); + ring_filter->setDropLoss(drop_loss + thru_loss * number_wavelengths); + // Update area + getAreaResult("Photonic")->setValue(ring_area * (number_wavelengths)); + } + +} // namespace DSENT + diff --git a/ext/dsent/model/optical/RingFilter.h b/ext/dsent/model/optical/RingFilter.h new file mode 100644 index 000000000..87fcb8c04 --- /dev/null +++ b/ext/dsent/model/optical/RingFilter.h @@ -0,0 +1,30 @@ +#ifndef __DSENT_MODEL_OPTICAL_RINGFILTER_H__ +#define __DSENT_MODEL_OPTICAL_RINGFILTER_H__ + +#include "util/CommonType.h" +#include "model/OpticalModel.h" + +namespace DSENT +{ + class RingFilter : public OpticalModel + { + public: + RingFilter(const String& instance_name_, const TechModel* tech_model_); + virtual ~RingFilter(); + + public: + // Set a list of properties' name needed to construct model + void initParameters(); + // Set a list of properties' name needed to construct model + void initProperties(); + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + + }; // class RingFilter +} // namespace DSENT + +#endif // __DSENT_MODEL_OPTICAL_RINGFILTER_H__ + diff --git a/ext/dsent/model/optical/RingModulator.cc b/ext/dsent/model/optical/RingModulator.cc new file mode 100644 index 000000000..8fe320fbd --- /dev/null +++ b/ext/dsent/model/optical/RingModulator.cc @@ -0,0 +1,403 @@ +#include "model/optical/RingModulator.h" + +#include <cmath> + +#include "util/Constants.h" +#include "model/PortInfo.h" +#include "model/TransitionInfo.h" +#include "model/EventInfo.h" +#include "model/std_cells/StdCell.h" +#include "model/std_cells/StdCellLib.h" +#include "model/optical_graph/OpticalWaveguide.h" +#include "model/optical_graph/OpticalModulator.h" +#include "model/optical_graph/OpticalFilter.h" +#include "model/optical_graph/OpticalTransmitter.h" +#include "model/timing_graph/ElectricalNet.h" +#include "model/timing_graph/ElectricalLoad.h" +#include "model/timing_graph/ElectricalTimingTree.h" + +namespace DSENT +{ + using std::max; + using std::min; + + // TODO: Don't like the way this is written right now. Probably fix in a future version + + RingModulator::RingModulator(const String& instance_name_, const TechModel* tech_model_) + : OpticalModel(instance_name_, tech_model_) + { + initParameters(); + initProperties(); + } + + RingModulator::~RingModulator() + {} + + void RingModulator::initParameters() + { + addParameterName("DataRate"); + addParameterName("InStart"); + addParameterName("InEnd"); + addParameterName("ModStart"); + addParameterName("ModEnd"); + addParameterName("OptimizeLoss", "TRUE"); + return; + } + + void RingModulator::initProperties() + { + addPropertyName("ExtinctionRatio", 6); //default properties + addPropertyName("InsertionLoss", 2); //default properties + return; + } + + void RingModulator::constructModel() + { + // Create electrical results + createElectricalAtomicResults(); + // Create Area result + addAreaResult(new AtomicResult("Photonic")); + // Create Modulate result + createElectricalEventAtomicResult("Modulate"); + + // Get parameters + WavelengthGroup in_wavelengths = makeWavelengthGroup(getParameter("InStart"), getParameter("InEnd")); + WavelengthGroup mod_wavelengths = makeWavelengthGroup(getParameter("ModStart"), getParameter("ModEnd")); + int number_wavelengths = mod_wavelengths.second - mod_wavelengths.first + 1; + bool optimize_loss = getParameter("OptimizeLoss"); + + getGenProperties()->set("NumberWavelengths", number_wavelengths); + + // Create optical ports + createOpticalInputPort( "In", in_wavelengths); + createOpticalOutputPort( "Out", in_wavelengths); + // Create the filter and modulator + createFilter( "RingFilter", in_wavelengths, true, mod_wavelengths); + createModulator( "RingModulator", mod_wavelengths, optimize_loss, this); + createWaveguide( "RingTemp", mod_wavelengths); + OpticalFilter* ring_filter = getFilter("RingFilter"); + OpticalModulator* ring_modulator = getModulator("RingModulator"); + // Connect the filter and modulator + getWaveguide("In")->addDownstreamNode(ring_filter); + ring_filter->addDownstreamNode(getWaveguide("Out")); + ring_filter->setDropPort(ring_modulator); + ring_modulator->addDownstreamNode(getWaveguide("Out")); + + // Create electrical ports + createInputPort( "In", makeNetIndex(0, number_wavelengths-1)); + // Create driver + createNet("PredriverIn"); + // VFI from In to PredriverIn + assignVirtualFanin("PredriverIn", "In"); + // Create input load (due to predrivers) + createLoad("PredriverCap"); + getNet("PredriverIn")->addDownstreamNode(getLoad("PredriverCap")); + + // Precompute some values + precomputeTech(); + + return; + } + + void RingModulator::updateModel() + { + // Get properties + double ER_dB = getProperty("ExtinctionRatio").toDouble(); + double IL_dB = getProperty("InsertionLoss").toDouble(); + + // Get Gen properties + int number_wavelengths = getGenProperties()->get("NumberWavelengths"); + + // Get tech model parameters + double ring_area = getTechModel()->get("Ring->Area").toDouble(); + double thru_loss = getTechModel()->get("Ring->ThroughLoss").toDouble(); + + // Design the modulator and the modulator driver + bool success = designModulator(IL_dB, ER_dB); + getGenProperties()->set("Success", success); + + // If not successful, make the modulate energy extremely large + if (!success) getEventResult("Modulate")->setValue(1e99); + + // Update losses + // Connect the filter and modulator + OpticalFilter* ring_filter = getFilter("RingFilter"); + ring_filter->setLoss(thru_loss * number_wavelengths); + ring_filter->setDropLoss(thru_loss * number_wavelengths); // Assume worst-case through loss for a dropped wavelength + // Update area + getAreaResult("Photonic")->setValue(ring_area * (number_wavelengths)); + } + + void RingModulator::useModel() + { + // Propagate the transition info and get the 0->1 transtion count + propagateTransitionInfo(); + double P_In = getInputPort("In")->getTransitionInfo().getProbability1(); + double P_num_trans_01 = getInputPort("In")->getTransitionInfo().getNumberTransitions01(); + + // Get Gen properties + int number_wavelengths = getGenProperties()->get("NumberWavelengths"); + + // If I can't build it...then it is infinitely expensive! + bool success = getGenProperties()->get("Success"); + double driver_size = 1e99; + double total_predriver_size = 1e99; + if (success) + { + driver_size = getGenProperties()->get("DriverSize"); + total_predriver_size = getGenProperties()->get("TotalPredriverSize"); + } + + // Get parameters corresponding to a unit-inverter + double unit_leak_0 = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Leakage->!A"); + double unit_leak_1 = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Leakage->A"); + + // Approximate leakage + double total_leakage = number_wavelengths * 0.5 * ((driver_size + total_predriver_size) * P_In * unit_leak_1 + + (driver_size + total_predriver_size) * (1 - P_In) * unit_leak_0); + + getNddPowerResult("Leakage")->setValue(total_leakage); + getEventResult("Modulate")->setValue(calcModulatorEnergy() * P_num_trans_01); + + return; + } + + void RingModulator::propagateTransitionInfo() + { + // Very simple...whatever comes in electrically is encoded optically + getOpticalOutputPort("Out")->setTransitionInfo(getInputPort("In")->getTransitionInfo()); + + return; + } + + void RingModulator::precomputeTech() + { + // Get parameters + double data_rate = getParameter("DataRate"); + + // Constants shortcuts + double pi = Constants::pi; + double c = Constants::c; + double k = Constants::k; + double e0 = Constants::e0; + double es = Constants::es; + double q = Constants::q; + double T = getTechModel()->get("Temperature"); + + // Get modulator parameters + double lambda = getTechModel()->get("Ring->Lambda").toDouble(); + double n_f = getTechModel()->get("Modulator->Ring->FCPDEffect").toDouble(); + double NA = getTechModel()->get("Modulator->Ring->NA").toDouble(); + double ND = getTechModel()->get("Modulator->Ring->ND").toDouble(); + double ni = getTechModel()->get("Modulator->Ring->ni").toDouble(); + double L_j = getTechModel()->get("Modulator->Ring->JunctionRatio").toDouble(); + double H = getTechModel()->get("Modulator->Ring->Height").toDouble(); + double W = getTechModel()->get("Modulator->Ring->Width").toDouble(); + double g_c = getTechModel()->get("Modulator->Ring->ConfinementFactor").toDouble(); + // Get ring parameters + double R = getTechModel()->get("Ring->Radius").toDouble(); + double n_g = getTechModel()->get("Ring->GroupIndex").toDouble(); + double Q_max = getTechModel()->get("Ring->MaxQualityFactor").toDouble(); + + // Setup calculations + double f0 = c / lambda; + double BW = data_rate; // Modulator bandwidth + double Q_f = std::min(f0 / BW, Q_max); // Quality factor + double L_tot = 2 * pi * R; // Optical length of the ring + + double V_bi = k * T / q * log(NA * ND / (ni * ni)); // Junction Built-in voltage + double x_d0 = sqrt(2 * e0 * es / q * V_bi * (NA + ND) / (NA * ND)); // Junction nominal depletion width + double C_j0 = e0 * es * L_tot * L_j * W / x_d0; // Junction nominal cap + double Q_0 = q * n_g * (L_tot * H * W) / (2 * n_f * Q_f * g_c); // Charge in depletion region + + // Store into precomputed values + m_precompute_V_bi_ = V_bi; + m_precompute_x_d0_ = x_d0; + m_precompute_C_j0_ = C_j0; + m_precompute_Q_0_ = Q_0; + + return; + } + + bool RingModulator::designModulator(double IL_dB_, double ER_dB_) + { + // Get parameters + double vdd = getTechModel()->get("Vdd"); + double data_rate = getParameter("DataRate"); + unsigned int max_predriver_stages = 20; //TODO: Make this not hardcoded + // Get modulator parameters + double boost_ratio = getTechModel()->get("Modulator->Ring->SupplyBoostRatio"); + double Tn = getTechModel()->get("Modulator->Ring->Tn").toDouble();; + double H = getTechModel()->get("Modulator->Ring->Height").toDouble(); + + // Get Gen properties + int number_wavelengths = getGenProperties()->get("NumberWavelengths"); + + // Checking ASSERTions (input properties that don't make any sense) + ASSERT(ER_dB_ > 0, "[Error] " + getInstanceName() + " -> Extinction ratio must be > 0!"); + ASSERT(IL_dB_ > 0, "[Error] " + getInstanceName() + " -> Insertion loss must be > 0!"); + + // Setup calculations + double ER = pow(10, ER_dB_ / 10); // Extinction ratio + double T1 = pow(10, -IL_dB_ / 10); // Transmisivity on + double T0 = T1 / ER; // Transmisivity off + + // Get precomputed values + double V_bi = m_precompute_V_bi_; + double x_d0 = m_precompute_x_d0_; + double C_j0 = m_precompute_C_j0_; + double Q_0 = m_precompute_Q_0_; + + // Charge + double int_c = -2 * V_bi * C_j0; + // Calculate shift using lorentzian + double gamma = sqrt((1 - Tn)/(1 - T1) - 1) - sqrt((1 - Tn)/(1 - T0) - 1); // gamma = delta_f / delta_f_FWHM + double Q = gamma * Q_0; // Charge required to hit given Tf + // Voltage required + double V_a = V_bi * (pow( (Q - int_c)/(2 * V_bi * C_j0), 2) - 1); + // Calculate driver vdd + double hvdd = V_a * boost_ratio; + // Depletion region required + double x_d = x_d0 * sqrt((V_bi + V_a) / V_bi); + + // Calculate C_eff + double c_eff = Q / V_a; + + // Feasibility checks + // Not feasible if the transmisivity when transmitting an optical 1 is greater than 1.0... + if (T1 >= 1) return false; + // Not feasible if the transmisivity when transmitting an optical 0 is smaller than the notch of the ring + if (T0 <= Tn) return false; + // Not feasible if the extinction ratio is greater than the notch of the ring + if (ER >= 1 / Tn) return false; + // Not feasible if the required depletion width is greater than the height of the junction + if (x_d >= H) return false; + + // Analytically calculate driver sizes + // Get parameters corresponding to a unit-inverter + double unit_c_g = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->A"); + double unit_c_d = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->Y"); + double unit_r_o = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->DriveRes->Y"); + double unit_area_active = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Area->Active"); + double unit_area_metal1 = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Area->Metal1Wire"); + + // Get device resistance/cap + double device_par_res = getTechModel()->get("Modulator->Ring->ParasiticRes"); + double device_par_cap = getTechModel()->get("Modulator->Ring->ParasiticCap"); + + // Use timing tree to size modulator drivers + // Coefficient of R*C to give a 0->V_a transition + double transition_scale = log(hvdd / (hvdd - V_a)); + double transition_required = 1 / (4 * data_rate); // I am not sure what the factor of 4 is for... + + // Calculate inverter intrinsic transition time + double transition_intrinsic = transition_scale * unit_c_d * unit_r_o; + // Calculate minimum possible device transition time + double min_transition_intrinsic = transition_intrinsic + transition_scale * device_par_res * c_eff; + // If the minimum possible transition time is already bigger + // than the required transition, then this particular driver is not possible... + if (min_transition_intrinsic > transition_required) + return false; + + // Calculate driver size + double driver_size = max(1.0, transition_scale * unit_r_o * (c_eff + device_par_cap) / (transition_required - min_transition_intrinsic)); + // Keep track of the total multiplier of unit inverters (for area, leakage calculations) + double total_unit_inverters = driver_size * max(1.0, hvdd / vdd); + // Calculate load cap for predriver stages + double current_load_cap = driver_size * unit_c_g; + // Number of predriver stages + unsigned int predriver_stages = 0; + // Add predriver stages until the input cap is less than the unit INV_X1 gate cap or + // if the signal is still inverted (need an odd number of predriver stages) + while (current_load_cap > unit_c_g || (predriver_stages == 0) || ((predriver_stages & 0x1) == 0)) + { + // Calculate the size of the current predriver stage + double current_predriver_size = max(1.0, unit_r_o * current_load_cap / (transition_required - transition_intrinsic)); + // Calculate load cap for the next predriver stage + current_load_cap = current_predriver_size * unit_c_g; + // Add cap to total predriver total cap + total_unit_inverters += current_predriver_size; + // Consider this a failure if the number of predriver stages exceed some maximum + if (predriver_stages > max_predriver_stages) + return false; + + ++predriver_stages; + } + // Set the input load capacitance + getLoad("PredriverCap")->setLoadCap(current_load_cap); + + // Set generated properties + getGenProperties()->set("DriverSize", driver_size); + getGenProperties()->set("FirstPredriverSize", current_load_cap); + getGenProperties()->set("TotalPredriverSize", total_unit_inverters - driver_size); + getGenProperties()->set("Hvdd", hvdd); + getGenProperties()->set("Ceff", c_eff); + + // Calculate leakage, area, energy consumption + double area_active = total_unit_inverters * unit_area_active; + double area_metal1 = total_unit_inverters * unit_area_metal1; + + // Set results + getAreaResult("Active")->setValue(area_active * number_wavelengths); + getAreaResult("Metal1Wire")->setValue(area_metal1 * number_wavelengths); + + // Only if everything was successful do we set the modulator specification + getModulator("RingModulator")->setLosses(IL_dB_, ER_dB_); + return true; + } + + double RingModulator::calcModulatorEnergy() const + { + // Get tech parameters + double vdd = getTechModel()->get("Vdd"); + double device_par_cap = getTechModel()->get("Modulator->Ring->ParasiticCap"); + + // Get Gen properties + int number_wavelengths = getGenProperties()->get("NumberWavelengths"); + + bool success = getGenProperties()->get("Success"); + if (success) + { + double driver_size = getGenProperties()->get("DriverSize"); + double total_predriver_size = getGenProperties()->get("TotalPredriverSize"); + double first_predriver_size = getGenProperties()->get("FirstPredriverSize"); + double c_eff = getGenProperties()->get("Ceff"); + double hvdd = getGenProperties()->get("Hvdd"); + + // Get parameters corresponding to a unit-inverter + double unit_c_g = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->A"); + double unit_c_d = getTechModel()->getStdCellLib()->getStdCellCache()->get("INV_X1->Cap->Y"); + + // Approximate leakage + double energy_predriver = number_wavelengths * vdd * vdd * ((unit_c_d * total_predriver_size + + unit_c_g * (total_predriver_size + driver_size - first_predriver_size))); + double energy_driver = number_wavelengths * hvdd * std::max(hvdd, vdd) * (driver_size * unit_c_d + c_eff + device_par_cap); + + return (energy_predriver + energy_driver); + } + else + return 1e99; // An infinitely expensive modulator + } + + bool RingModulator::setTransmitterSpec(double IL_dB_, double ER_dB_) + { + setProperty("InsertionLoss", IL_dB_); + setProperty("ExtinctionRatio", ER_dB_); + update(); + evaluate(); + + return getGenProperties()->get("Success"); + } + + double RingModulator::getPower(double util_) const + { + // Get parameters + double data_rate = getParameter("DataRate"); + // Check arguments + ASSERT((util_ <= 1.0) && (util_ >= 0.0), "[Error] " + getInstanceName() + " -> Modulator utilization must be between 0.0 and 1.0!"); + + return calcModulatorEnergy() * 0.25 * util_ * data_rate; + } + +} // namespace DSENT + diff --git a/ext/dsent/model/optical/RingModulator.h b/ext/dsent/model/optical/RingModulator.h new file mode 100644 index 000000000..bbfa7f4ee --- /dev/null +++ b/ext/dsent/model/optical/RingModulator.h @@ -0,0 +1,54 @@ +#ifndef __DSENT_MODEL_OPTICAL_RINGMODULATOR_H__ +#define __DSENT_MODEL_OPTICAL_RINGMODULATOR_H__ + +#include "util/CommonType.h" +#include "model/OpticalModel.h" +#include "model/optical_graph/OpticalTransmitter.h" + +namespace DSENT +{ + class RingModulator : public OpticalModel, public OpticalTransmitter + { + public: + RingModulator(const String& instance_name_, const TechModel* tech_model_); + virtual ~RingModulator(); + + public: + // Set a list of properties' name needed to construct model + void initParameters(); + // Set a list of properties' name needed to construct model + void initProperties(); + // Set the transmitter specifications, returns whether it is possible + // to build a modulator that met those specs + bool setTransmitterSpec(double IL_dB_, double ER_dB_); + // Returns power of the transmitter at a given utilization + double getPower(double util_) const; + + private: + // Precompute values based on tech parameters + void precomputeTech(); + // Design ring modulator driver + bool designModulator(double IL_dB_, double ER_dB_); + // Calculate modulator energy + double calcModulatorEnergy() const; + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void useModel(); + virtual void propagateTransitionInfo(); + + private: + // Some precomputed tech values + double m_precompute_V_bi_; + double m_precompute_x_d0_; + double m_precompute_C_j0_; + double m_precompute_Q_0_; + + + }; // class RingModulator +} // namespace DSENT + +#endif // __DSENT_MODEL_OPTICAL_RINGMODULATOR_H__ + diff --git a/ext/dsent/model/optical/SWMRLink.cc b/ext/dsent/model/optical/SWMRLink.cc new file mode 100644 index 000000000..56d2d70b3 --- /dev/null +++ b/ext/dsent/model/optical/SWMRLink.cc @@ -0,0 +1,309 @@ +#include "model/optical/SWMRLink.h" + +#include "model/PortInfo.h" +#include "model/TransitionInfo.h" +#include "model/EventInfo.h" +#include "model/optical_graph/OpticalGraph.h" +#include "model/optical_graph/OpticalWaveguide.h" +#include "model/optical/RingModulator.h" +#include "model/optical/RingFilter.h" +#include "model/optical/RingDetector.h" +#include "model/optical/LaserSource.h" +#include "model/optical/ThrottledLaserSource.h" + +namespace DSENT +{ + SWMRLink::SWMRLink(const String& instance_name_, const TechModel* tech_model_) + : OpticalModel(instance_name_, tech_model_) + { + initParameters(); + initProperties(); + } + + SWMRLink::~SWMRLink() + {} + + void SWMRLink::initParameters() + { + addParameterName("NumberReaders"); + addParameterName("NumberWavelengths"); + addParameterName("DataRate"); + addParameterName("LaserType"); + addParameterName("MaxReaders"); + addParameterName("MinReaders"); + addParameterName("OptimizeLoss", "TRUE"); + return; + } + + void SWMRLink::initProperties() + { + addPropertyName("Length"); + addPropertyName("OptUtil", 0.5); // default to 50% utilization (a new word 50% of the time) + addPropertyName("ExtinctionRatio", 6); // default properties + addPropertyName("InsertionLoss", 2); // default properties + return; + } + + void SWMRLink::constructModel() + { + // Get parameters + unsigned int number_wavelengths = getParameter("NumberWavelengths"); + unsigned int number_readers = getParameter("NumberReaders"); + unsigned int number_max_readers = std::min(number_readers, getParameter("MaxReaders").toUInt()); + unsigned int number_min_readers = std::min(number_max_readers, getParameter("MinReaders").toUInt()); + + // Create electrical ports + createInputPort("CK"); + createInputPort("In", makeNetIndex(0, number_wavelengths-1)); + for (unsigned int i = 0; i < number_readers; ++i) + createOutputPort("Out" + (String) i, makeNetIndex(0, number_wavelengths-1)); + + // Create Waveguides + // Temporarily assume its all on one waveguide + createWaveguide("LaserToMod", makeWavelengthGroup(0, number_wavelengths-1)); + for (unsigned int i = 0; i <= number_readers; ++i) + createWaveguide("WaveguideSegment[" + (String) i + "]", makeWavelengthGroup(0, number_wavelengths-1)); + + // Add area results + addAreaResult(new Result("Photonic")); + createElectricalResults(); + // Setup idle event + getEventInfo("Idle")->setStaticTransitionInfos(); + // Create a waveguide area result + addAreaResult(new AtomicResult("Waveguide")); + getAreaResult("Photonic")->addSubResult(getAreaResult("Waveguide"), "Waveguide", 1.0); + // Add results + addNddPowerResult(new Result("Laser")); + // Add event result + createElectricalEventResult("BroadcastFlit"); + + for (unsigned int i = number_min_readers; i <= number_max_readers; ++i) + createElectricalEventResult("MulticastFlit" + (String) i); + + buildLaser(); + buildModulator(); + buildDetectors(); + + return; + } + + void SWMRLink::updateModel() + { + // Get parameters + double data_rate = getParameter("DataRate"); + unsigned int number_readers = getParameter("NumberReaders"); + + // Get properties + double length = getProperty("Length"); + const String& extinction_ratio = getProperty("ExtinctionRatio"); + const String& insertion_loss = getProperty("InsertionLoss"); + const double opt_util = getProperty("OptUtil"); + + // Calculate loss for each waveguide segment + double segment_length = (double) length / number_readers; + double segment_loss = getTechModel()->get("Waveguide->LossPerMeter").toDouble() * segment_length; + // Set loss of each waveguide segment + for (unsigned int i = 0; i < number_readers; ++i) + getWaveguide("WaveguideSegment[" + (String) i + "]")->setLoss(segment_loss); + // Calculate waveguide area + double waveguide_area = length * getTechModel()->get("Waveguide->Pitch").toDouble(); + getAreaResult("Waveguide")->setValue(waveguide_area); + + // Update the laser + Model* laser = getSubInstance("Laser"); + laser->setProperty("LaserEventTime", 1.0 / data_rate); + laser->setProperty("OptUtil", opt_util); + laser->update(); + + // Update the modulator + Model* modulator = getSubInstance("Modulator"); + modulator->setProperty("ExtinctionRatio", extinction_ratio); + modulator->setProperty("InsertionLoss", insertion_loss); + modulator->update(); + + // Update all receivers + for (unsigned int i = 0; i < number_readers; ++i) + { + Model* detector = getSubInstance("Detector_" + (String) i); + detector->update(); + } + + return; + } + + void SWMRLink::propagateTransitionInfo() + { + // Get parameters + const String& laser_type = getParameter("LaserType"); + unsigned int number_readers = getParameter("NumberReaders"); + + // Set transition info for the modulator + OpticalModel* modulator = (OpticalModel*) getSubInstance("Modulator"); + propagatePortTransitionInfo(modulator, "In", "In"); + modulator->use(); + + // Modulator out transition info + const TransitionInfo& mod_out_transitions = modulator->getOpticalOutputPort("Out")->getTransitionInfo(); + + // Set transition info for all receivers + for (unsigned int i = 0; i < number_readers; ++i) + { + OpticalModel* detector = (OpticalModel*) getSubInstance("Detector_" + (String) i); + detector->getOpticalInputPort("In")->setTransitionInfo(mod_out_transitions); + detector->use(); + + // Propagate output transition info to output + propagatePortTransitionInfo("Out" + (String) i, detector, "Out"); + } + + // Set enable signals for the laser, if applicable + if (laser_type == "Throttled") + { + // Figure out how many cycles the laser needs to be on + double cycles = getInputPort("In")->getTransitionInfo().getFrequencyMultiplier(); + + OpticalModel* laser = (OpticalModel*) getSubInstance("Laser"); + laser->getInputPort("LaserEnable")->setTransitionInfo(TransitionInfo(0.0, 1.0, cycles - 1.0)); + laser->use(); + } + return; + } + + void SWMRLink::buildLaser() + { + // Get parameters + unsigned int number_wavelengths = getParameter("NumberWavelengths"); + unsigned int number_readers = getParameter("NumberReaders"); + unsigned int number_max_readers = std::min(number_readers, getParameter("MaxReaders").toUInt()); + unsigned int number_min_readers = std::min(number_max_readers, getParameter("MinReaders").toUInt()); + const String& laser_type = getParameter("LaserType"); + + // Create laser + OpticalModel* laser = NULL; + if (laser_type == "Throttled") + laser = new ThrottledLaserSource("Laser", getTechModel()); + else if (laser_type == "Standard") + laser = new LaserSource("Laser", getTechModel()); + else + ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown laser type '" + laser_type + "'!"); + + laser->setParameter("OutStart", 0); + laser->setParameter("OutEnd", number_wavelengths-1); + laser->setParameter("MaxDetectors", number_max_readers); + laser->setParameter("MinDetectors", number_min_readers); + laser->construct(); + + addSubInstances(laser, 1.0); + getAreaResult("Photonic")->addSubResult(laser->getAreaResult("Photonic"), "Laser", 1.0); + // Connect laser output port + opticalPortConnect(laser, "Out", "LaserToMod"); + + // Without laser gating, laser is pure NDD power + if (laser_type == "Standard") + getNddPowerResult("Laser")->addSubResult(laser->getNddPowerResult("Laser"), "Laser", 1.0); + // With laser power gating, laser is an event + else + { + // If laser is throttled, only pay for the amount needed to reach some number of readers + getEventResult("BroadcastFlit")->addSubResult(laser->getEventResult("Laser" + (String) number_max_readers), "Laser", 1.0); + for (unsigned int i = number_min_readers; i <= number_max_readers; ++i) + getEventResult("MulticastFlit" + (String) i)->addSubResult(laser->getEventResult("Laser" + (String) i), "Laser", 1.0); + } + + return; + } + + void SWMRLink::buildModulator() + { + // Get parameters + double data_rate = getParameter("DataRate"); + const String& optimize_loss = getParameter("OptimizeLoss"); + unsigned int number_wavelengths = getParameter("NumberWavelengths"); + unsigned int number_readers = getParameter("NumberReaders"); + unsigned int number_max_readers = std::min(number_readers, getParameter("MaxReaders").toUInt()); + unsigned int number_min_readers = std::min(number_max_readers, getParameter("MinReaders").toUInt()); + + // Create modulator + RingModulator* modulator = new RingModulator("Modulator", getTechModel()); + modulator->setParameter("DataRate", data_rate); + modulator->setParameter("InStart", 0); + modulator->setParameter("InEnd", number_wavelengths-1); + modulator->setParameter("ModStart", 0); + modulator->setParameter("ModEnd", number_wavelengths-1); + modulator->setParameter("OptimizeLoss", optimize_loss); + modulator->construct(); + addSubInstances(modulator, 1.0); + getAreaResult("Photonic")->addSubResult(modulator->getAreaResult("Photonic"), "Modulator", 1.0); + addElectricalSubResults(modulator, 1.0); + + // Connect electrical port + portConnect(modulator, "In", "In"); + // Connect modulator input, output port + opticalPortConnect(modulator, "In", "LaserToMod"); + opticalPortConnect(modulator, "Out", "WaveguideSegment[0]"); + + // Add modulator energy event for all broadcast events + getEventResult("BroadcastFlit")->addSubResult(modulator->getEventResult("Modulate"), "Modulator", 1.0); + for (unsigned int i = number_min_readers; i <= number_max_readers; ++i) + getEventResult("MulticastFlit" + (String) i)->addSubResult(modulator->getEventResult("Modulate"), "Modulator", 1.0); + + return; + } + + void SWMRLink::buildDetectors() + { + // Get parameters + double data_rate = getParameter("DataRate"); + unsigned int number_wavelengths = getParameter("NumberWavelengths"); + unsigned int number_readers = getParameter("NumberReaders"); + unsigned int number_max_readers = std::min(number_readers, getParameter("MaxReaders").toUInt()); + unsigned int number_min_readers = std::min(number_max_readers, getParameter("MinReaders").toUInt()); + + // Create a SWMR Configuration + for (unsigned int i = 0; i < number_readers; ++i) + { + String n = (String) i; + + // Create resonant ring detector + RingDetector* detector = new RingDetector("Detector_" + n, getTechModel()); + detector->setParameter("DataRate", data_rate); + detector->setParameter("InStart", 0); + detector->setParameter("InEnd", number_wavelengths-1); + detector->setParameter("DetStart", 0); + detector->setParameter("DetEnd", number_wavelengths-1); + detector->setParameter("DropAll", "FALSE"); + detector->setParameter("Topology", RingDetector::INTEGRATINGSENSEAMP); + detector->construct(); + addSubInstances(detector, 1.0); + getAreaResult("Photonic")->addSubResult(detector->getAreaResult("Photonic"), "Detector_" + n, 1.0); + addElectricalSubResults(detector, 1.0); + + // connect to electrical port + portConnect(detector, "Out", "Out" + (String) i); + // connect optical input, output port + opticalPortConnect(detector, "In", "WaveguideSegment[" + (String) i + "]"); + opticalPortConnect(detector, "Out", "WaveguideSegment[" + (String) (i + 1) + "]"); + } + + // Add an average receiver energy for all multicast events (and broadcast) + Result* broadcast_event = getEventResult("BroadcastFlit"); + for (unsigned int i = 0; i < number_readers; ++i) + { + const String detector_name = "Detector_" + (String) i; + broadcast_event->addSubResult(getSubInstance(detector_name)->getEventResult("Receive"), detector_name, 1.0); + } + for (unsigned int i = number_min_readers; i <= number_max_readers; ++i) + { + Result* multicast_event = getEventResult("MulticastFlit" + (String) i); + for (unsigned int j = 0; j < number_readers; ++j) + { + const String detector_name = "Detector_" + (String) j; + multicast_event->addSubResult(getSubInstance(detector_name)->getEventResult("Receive"), detector_name, (double) i / number_readers); + } + } + + return; + } + +} // namespace DSENT + diff --git a/ext/dsent/model/optical/SWMRLink.h b/ext/dsent/model/optical/SWMRLink.h new file mode 100644 index 000000000..a2618358c --- /dev/null +++ b/ext/dsent/model/optical/SWMRLink.h @@ -0,0 +1,38 @@ +#ifndef __DSENT_MODEL_OPTICAL_SWMRLINK_H__ +#define __DSENT_MODEL_OPTICAL_SWMRLINK_H__ + +#include "util/CommonType.h" +#include "model/OpticalModel.h" + +namespace DSENT +{ + class SWMRLink : public OpticalModel + { + // A SWMR Link consists of a laser, a modulator (the writer) and a variable + // number of readers + public: + SWMRLink(const String& instance_name_, const TechModel* tech_model_); + virtual ~SWMRLink(); + + public: + // Set a list of properties' name needed to construct model + void initParameters(); + // Set a list of properties' name needed to construct model + void initProperties(); + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void propagateTransitionInfo(); + + private: + void buildLaser(); + void buildModulator(); + void buildDetectors(); + + }; // class SWMRLink +} // namespace DSENT + +#endif // __DSENT_MODEL_OPTICAL_SWMRLINK_H__ + diff --git a/ext/dsent/model/optical/SWSRLink.cc b/ext/dsent/model/optical/SWSRLink.cc new file mode 100644 index 000000000..88973e392 --- /dev/null +++ b/ext/dsent/model/optical/SWSRLink.cc @@ -0,0 +1,328 @@ +#include "model/optical/SWSRLink.h" + +#include "model/ModelGen.h" +#include "model/PortInfo.h" +#include "model/TransitionInfo.h" +#include "model/EventInfo.h" +#include "model/optical_graph/OpticalGraph.h" +#include "model/optical_graph/OpticalWaveguide.h" +#include "model/optical/RingModulator.h" +#include "model/optical/RingFilter.h" +#include "model/optical/RingDetector.h" +#include "model/optical/LaserSource.h" +#include "model/optical/ThrottledLaserSource.h" + +namespace DSENT +{ + SWSRLink::SWSRLink(const String& instance_name_, const TechModel* tech_model_) + : OpticalModel(instance_name_, tech_model_) + { + initParameters(); + initProperties(); + } + + SWSRLink::~SWSRLink() + {} + + void SWSRLink::initParameters() + { + addParameterName("NumberBits"); + addParameterName("CoreDataRate"); + addParameterName("LinkDataRate"); + + addParameterName("LaserType"); + addParameterName("RingTuningMethod"); + addParameterName("OptimizeLoss", "TRUE"); + + return; + } + + void SWSRLink::initProperties() + { + addPropertyName("Length"); + addPropertyName("OptUtil", 0.5); // default to 50% utilization (a new word 50% of the time) + addPropertyName("ExtinctionRatio", 6); // default properties + addPropertyName("InsertionLoss", 2); // default properties + return; + } + + void SWSRLink::constructModel() + { + // Get parameters + unsigned int number_bits = getParameter("NumberBits"); + double core_data_rate = getParameter("CoreDataRate"); + double link_data_rate = getParameter("LinkDataRate"); + + // Get directly propagated parameters + const String& ring_tuning_method = getParameter("RingTuningMethod"); + + // Calculate number of wavelengths needed + unsigned int number_wavelengths = (unsigned int)((double) number_bits * core_data_rate / link_data_rate); + + // Set some generated properties + getGenProperties()->set("NumberWavelengths", number_wavelengths); + + // Create electrical ports + createInputPort("LinkCK"); + createInputPort("In", makeNetIndex(0, number_bits-1)); + createOutputPort("Out", makeNetIndex(0, number_bits-1)); + + // Create Waveguides + // Temporarily assume its all on one waveguide + createWaveguide("LaserToMod", makeWavelengthGroup(0, number_wavelengths-1)); + createWaveguide("ModToDetector", makeWavelengthGroup(0, number_wavelengths-1)); + + // Add area results + addAreaResult(new Result("Photonic")); + createElectricalResults(); + // Setup idle event + getEventInfo("Idle")->setStaticTransitionInfos(); + // Create a waveguide area result + addAreaResult(new AtomicResult("Waveguide")); + getAreaResult("Photonic")->addSubResult(getAreaResult("Waveguide"), "Waveguide", 1.0); + // Add results + addNddPowerResult(new Result("Laser")); + addNddPowerResult(new Result("RingTuning")); + // Add event result + createElectricalEventResult("Send"); + + // Create Tx, Rx backends + // Create Tx electrical backend + ElectricalModel* tx_backend = (ElectricalModel*) ModelGen::createModel("OpticalLinkBackendTx", "OpticalLinkBackendTx", getTechModel()); + tx_backend->setParameter("InBits", number_bits); + tx_backend->setParameter("CoreDataRate", core_data_rate); + tx_backend->setParameter("LinkDataRate", link_data_rate); + tx_backend->setParameter("RingTuningMethod", ring_tuning_method); + tx_backend->setParameter("BitDuplicate", "TRUE"); + tx_backend->construct(); + + // Create Rx electrical backend + ElectricalModel* rx_backend = (ElectricalModel*) ModelGen::createModel("OpticalLinkBackendRx", "OpticalLinkBackendRx", getTechModel()); + rx_backend->setParameter("OutBits", number_bits); + rx_backend->setParameter("CoreDataRate", core_data_rate); + rx_backend->setParameter("LinkDataRate", link_data_rate); + rx_backend->setParameter("RingTuningMethod", ring_tuning_method); + rx_backend->setParameter("BitDuplicate", "TRUE"); + rx_backend->construct(); + + // Connect ports + createNet("TxBackendToTx", makeNetIndex(0, number_wavelengths-1)); + createNet("RxToRxBackend", makeNetIndex(0, number_wavelengths-1)); + portConnect(tx_backend, "In", "In"); + portConnect(tx_backend, "Out", "TxBackendToTx"); + portConnect(tx_backend, "LinkCK", "LinkCK"); + portConnect(rx_backend, "In", "RxToRxBackend"); + portConnect(rx_backend, "Out", "Out"); + portConnect(rx_backend, "LinkCK", "LinkCK"); + + // Add instances + addSubInstances(tx_backend, 1.0); + addSubInstances(rx_backend, 1.0); + + // Add electrical results + addElectricalSubResults(tx_backend, 1.0); + addElectricalSubResults(rx_backend, 1.0); + + // Add tuning power result + getNddPowerResult("RingTuning")->addSubResult(tx_backend->getNddPowerResult("RingTuning"), "OpticalLinkBackendTx", 1.0); + getNddPowerResult("RingTuning")->addSubResult(rx_backend->getNddPowerResult("RingTuning"), "OpticalLinkBackendRx", 1.0); + + // Add event results + getEventInfo("Send")->setTransitionInfo("LinkCK", TransitionInfo(0.0, (double) link_data_rate / (core_data_rate * 2.0), 0.0)); + + getEventResult("Send")->addSubResult(tx_backend->getEventResult("ProcessBits"), "OpticalLinkBackendTx", 1.0); + getEventResult("Send")->addSubResult(rx_backend->getEventResult("ProcessBits"), "OpticalLinkBackendRx", 1.0); + + buildLaser(); + buildModulator(); + buildDetector(); + + return; + } + + void SWSRLink::updateModel() + { + // Get parameters + double link_data_rate = getParameter("LinkDataRate"); + + // Get properties + double length = getProperty("Length"); + const String& extinction_ratio = getProperty("ExtinctionRatio"); + const String& insertion_loss = getProperty("InsertionLoss"); + const double opt_util = getProperty("OptUtil"); + + // Calculate loss for waveguide + double waveguide_loss = getTechModel()->get("Waveguide->LossPerMeter").toDouble() * length; + // Set loss of the waveguide + getWaveguide("ModToDetector")->setLoss(waveguide_loss); + // Calculate waveguide area + double waveguide_area = length * getTechModel()->get("Waveguide->Pitch").toDouble(); + getAreaResult("Waveguide")->setValue(waveguide_area); + + // Update the laser + Model* laser = getSubInstance("Laser"); + laser->setProperty("LaserEventTime", 1.0 / link_data_rate); + laser->setProperty("OptUtil", opt_util); + laser->update(); + + // Update the modulator + Model* modulator = getSubInstance("Modulator"); + modulator->setProperty("ExtinctionRatio", extinction_ratio); + modulator->setProperty("InsertionLoss", insertion_loss); + modulator->update(); + + Model* detector = getSubInstance("Detector"); + detector->update(); + + Model* tx_backend = getSubInstance("OpticalLinkBackendTx"); + tx_backend->update(); + + Model* rx_backend = getSubInstance("OpticalLinkBackendRx"); + rx_backend->update(); + + return; + } + + void SWSRLink::propagateTransitionInfo() + { + // Get parameters + const String& laser_type = getParameter("LaserType"); + + // Propagate transition info to tx backend + OpticalModel* tx_backend = (OpticalModel*) getSubInstance("OpticalLinkBackendTx"); + propagatePortTransitionInfo(tx_backend, "In", "In"); + propagatePortTransitionInfo(tx_backend, "LinkCK", "LinkCK"); + tx_backend->use(); + + // Set transition info for the modulator + OpticalModel* modulator = (OpticalModel*) getSubInstance("Modulator"); + propagatePortTransitionInfo(modulator, "In", tx_backend, "Out"); + modulator->use(); + + // Modulator out transition info + const TransitionInfo& mod_out_transitions = modulator->getOpticalOutputPort("Out")->getTransitionInfo(); + + // Set transition info for the receiver + OpticalModel* detector = (OpticalModel*) getSubInstance("Detector"); + detector->getOpticalInputPort("In")->setTransitionInfo(mod_out_transitions); + detector->use(); + + // Propagate transition info to tx backend + OpticalModel* rx_backend = (OpticalModel*) getSubInstance("OpticalLinkBackendRx"); + propagatePortTransitionInfo(rx_backend, "In", detector, "Out"); + propagatePortTransitionInfo(rx_backend, "LinkCK", "LinkCK"); + rx_backend->use(); + + // Propagate output transition info to output + propagatePortTransitionInfo("Out", rx_backend, "Out"); + + // Set enable signals for the laser, if applicable + if (laser_type == "Throttled") + { + // Figure out how many cycles the laser needs to be on + double cycles = getInputPort("In")->getTransitionInfo().getFrequencyMultiplier(); + + OpticalModel* laser = (OpticalModel*) getSubInstance("Laser"); + laser->getInputPort("LaserEnable")->setTransitionInfo(TransitionInfo(0.0, 1.0, cycles - 1.0)); + laser->use(); + } + + + return; + } + + void SWSRLink::buildLaser() + { + // Get parameters + unsigned int number_wavelengths = getGenProperties()->get("NumberWavelengths"); + const String& laser_type = getParameter("LaserType"); + + // Create laser + OpticalModel* laser = NULL; + if (laser_type == "Throttled") laser = new ThrottledLaserSource("Laser", getTechModel()); + else if (laser_type == "Standard") laser = new LaserSource("Laser", getTechModel()); + else ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown laser type '" + laser_type + "'!"); + + laser->setParameter("OutStart", 0); + laser->setParameter("OutEnd", number_wavelengths-1); + laser->setParameter("MaxDetectors", 1); + laser->setParameter("MinDetectors", 1); + laser->construct(); + + addSubInstances(laser, 1.0); + getAreaResult("Photonic")->addSubResult(laser->getAreaResult("Photonic"), "Laser", 1.0); + // Connect laser output port + opticalPortConnect(laser, "Out", "LaserToMod"); + + // Without laser gating, laser is pure NDD power + if (laser_type == "Standard") getNddPowerResult("Laser")->addSubResult(laser->getNddPowerResult("Laser"), "Laser", 1.0); + // With laser power gating, laser is an event + else getEventResult("Send")->addSubResult(laser->getEventResult("Laser1"), "Laser", 1.0); + + return; + } + + void SWSRLink::buildModulator() + { + // Get parameters + double link_data_rate = getParameter("LinkDataRate"); + const String& optimize_loss = getParameter("OptimizeLoss"); + unsigned int number_wavelengths = getGenProperties()->get("NumberWavelengths"); + + // Create modulator + RingModulator* modulator = new RingModulator("Modulator", getTechModel()); + modulator->setParameter("DataRate", link_data_rate); + modulator->setParameter("InStart", 0); + modulator->setParameter("InEnd", number_wavelengths-1); + modulator->setParameter("ModStart", 0); + modulator->setParameter("ModEnd", number_wavelengths-1); + modulator->setParameter("OptimizeLoss", optimize_loss); + modulator->construct(); + addSubInstances(modulator, 1.0); + getAreaResult("Photonic")->addSubResult(modulator->getAreaResult("Photonic"), "Modulator", 1.0); + addElectricalSubResults(modulator, 1.0); + + // Connect electrical port + portConnect(modulator, "In", "TxBackendToTx"); + // Connect modulator input, output port + opticalPortConnect(modulator, "In", "LaserToMod"); + opticalPortConnect(modulator, "Out", "ModToDetector"); + + // Add modulator energy event for send events + getEventResult("Send")->addSubResult(modulator->getEventResult("Modulate"), "Modulator", 1.0); + return; + } + + void SWSRLink::buildDetector() + { + // Get parameters + double link_data_rate = getParameter("LinkDataRate"); + unsigned int number_wavelengths = getGenProperties()->get("NumberWavelengths"); + + // Create resonant ring detector + RingDetector* detector = new RingDetector("Detector", getTechModel()); + detector->setParameter("DataRate", link_data_rate); + detector->setParameter("InStart", 0); + detector->setParameter("InEnd", number_wavelengths-1); + detector->setParameter("DetStart", 0); + detector->setParameter("DetEnd", number_wavelengths-1); + detector->setParameter("DropAll", "TRUE"); + detector->setParameter("Topology", RingDetector::INTEGRATINGSENSEAMP); + detector->construct(); + addSubInstances(detector, 1.0); + getAreaResult("Photonic")->addSubResult(detector->getAreaResult("Photonic"), "Detector", 1.0); + addElectricalSubResults(detector, 1.0); + + // connect to electrical port + portConnect(detector, "Out", "RxToRxBackend"); + // connect optical input, output port + opticalPortConnect(detector, "In", "ModToDetector"); + + // Add receiver energy + getEventResult("Send")->addSubResult(detector->getEventResult("Receive"), "Detector", 1.0); + + return; + } + +} // namespace DSENT + diff --git a/ext/dsent/model/optical/SWSRLink.h b/ext/dsent/model/optical/SWSRLink.h new file mode 100644 index 000000000..fd6ecca73 --- /dev/null +++ b/ext/dsent/model/optical/SWSRLink.h @@ -0,0 +1,38 @@ +#ifndef __DSENT_MODEL_OPTICAL_SWSRLINK_H__ +#define __DSENT_MODEL_OPTICAL_SWSRLINK_H__ + +#include "util/CommonType.h" +#include "model/OpticalModel.h" + +namespace DSENT +{ + class SWSRLink : public OpticalModel + { + // A SWSR Link consists of a laser, a modulator (the writer) and a variable + // number of readers + public: + SWSRLink(const String& instance_name_, const TechModel* tech_model_); + virtual ~SWSRLink(); + + public: + // Set a list of properties' name needed to construct model + void initParameters(); + // Set a list of properties' name needed to construct model + void initProperties(); + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void propagateTransitionInfo(); + + private: + void buildLaser(); + void buildModulator(); + void buildDetector(); + + }; // class SWSRLink +} // namespace DSENT + +#endif // __DSENT_MODEL_OPTICAL_SWSRLINK_H__ + diff --git a/ext/dsent/model/optical/ThrottledLaserSource.cc b/ext/dsent/model/optical/ThrottledLaserSource.cc new file mode 100644 index 000000000..e95188b77 --- /dev/null +++ b/ext/dsent/model/optical/ThrottledLaserSource.cc @@ -0,0 +1,137 @@ +#include "model/optical/ThrottledLaserSource.h" + +#include "model/PortInfo.h" +#include "model/TransitionInfo.h" +#include "model/EventInfo.h" +#include "model/optical_graph/OpticalWaveguide.h" +#include "model/optical_graph/OpticalWavelength.h" +#include "model/optical_graph/OpticalLaser.h" +#include "model/optical_graph/OpticalGraph.h" + +namespace DSENT +{ + ThrottledLaserSource::ThrottledLaserSource(const String& instance_name_, const TechModel* tech_model_) + : OpticalModel(instance_name_, tech_model_), m_wavelength_(NULL) + { + initParameters(); + initProperties(); + } + + ThrottledLaserSource::~ThrottledLaserSource() + { + if (m_wavelength_ != NULL) delete m_wavelength_; + } + + void ThrottledLaserSource::initParameters() + { + addParameterName("OutStart"); + addParameterName("OutEnd"); + addParameterName("MaxDetectors"); + addParameterName("MinDetectors"); + return; + } + + void ThrottledLaserSource::initProperties() + { + addPropertyName("OptUtil", 1.0); + addPropertyName("LaserEventTime"); + return; + } + + void ThrottledLaserSource::constructModel() + { + // Get parameters + WavelengthGroup laser_wavelengths = makeWavelengthGroup(getParameter("OutStart"), getParameter("OutEnd")); + unsigned int max_detectors = getParameter("MaxDetectors").toUInt(); + unsigned int min_detectors = getParameter("MinDetectors").toUInt(); + + // Create electrical input port for laser control + createInputPort( "LaserEnable"); + + // Create Area result + addAreaResult(new AtomicResult("Photonic")); + // Create event result for each detector number possibility + for (unsigned int i = min_detectors; i <= max_detectors; ++i) + { + createElectricalEventAtomicResult("Laser" + (String) i); + getEventInfo("Laser" + (String) i)->setTransitionInfo("LaserEnable", TransitionInfo(0.0, 1.0, 0.0)); + } + + // Create optical ports + createOpticalOutputPort( "Out", laser_wavelengths); + // Create the filter + createLaser( "Laser", laser_wavelengths); + OpticalLaser* laser = getLaser("Laser"); + // Connect the laser to the output + laser->addDownstreamNode(getWaveguide("Out")); + } + + void ThrottledLaserSource::updateModel() + { + // Get properties + double laser_efficiency = getTechModel()->get("Laser->CW->Efficiency").toDouble(); + double laser_area = getTechModel()->get("Laser->CW->Area").toDouble(); + double laser_diode_loss = getTechModel()->get("Laser->CW->LaserDiodeLoss"); + + // Get parameters + WavelengthGroup laser_wavelengths = makeWavelengthGroup(getParameter("OutStart"), getParameter("OutEnd")); + unsigned int number_wavelengths = laser_wavelengths.second - laser_wavelengths.first + 1; + // Update losses + OpticalLaser* laser = getLaser("Laser"); + laser->setLoss(laser_diode_loss); + laser->setEfficiency(laser_efficiency); + // Update area + getAreaResult("Photonic")->setValue(laser_area * number_wavelengths); + } + + void ThrottledLaserSource::evaluateModel() + { + // Get parameters + unsigned int max_detectors = getParameter("MaxDetectors"); + WavelengthGroup laser_wavelengths = makeWavelengthGroup(getParameter("OutStart"), getParameter("OutEnd")); + + // Get properties + double opt_util = getProperty("OptUtil"); + + // Create optical graph object + OpticalGraph* optical_graph = new OpticalGraph("LaserTrace", this); + // Ask optical graph object to perform power optimization + bool success = optical_graph->performPowerOpt(getLaser("Laser"), laser_wavelengths, max_detectors, opt_util); + if (!success) + { + Log::printLine(std::cerr, "[Warning] " + getInstanceName() + + " -> Wavelengths contains data paths with no possible modulator configurations!"); + } + + // Trace the wavelengths the laser is outputting to find the output + // power needed by the laser + if (m_wavelength_ != NULL) delete m_wavelength_; + m_wavelength_ = optical_graph->traceWavelength(laser_wavelengths, getLaser("Laser")); + + delete optical_graph; + } + + void ThrottledLaserSource::useModel() + { + // Get parameters + unsigned int max_detectors = getParameter("MaxDetectors"); + unsigned int min_detectors = getParameter("MinDetectors"); + + // Get properties + double laser_event_time = getProperty("LaserEventTime"); + // Get laser enable information + const TransitionInfo& enable_info = getInputPort("LaserEnable")->getTransitionInfo(); + + for (unsigned int i = min_detectors; i <= max_detectors; ++i) + { + // Calculate the power needed by the wavelength + double laser_power = m_wavelength_->getLaserPower(i); + // Calculate the laser event power by calculating the amount + // of time the laser is on + getEventResult("Laser" + (String) i)->setValue(laser_power * laser_event_time * + enable_info.getFrequencyMultiplier() * enable_info.getProbability1()); + } + } + +} // namespace DSENT + diff --git a/ext/dsent/model/optical/ThrottledLaserSource.h b/ext/dsent/model/optical/ThrottledLaserSource.h new file mode 100644 index 000000000..117465419 --- /dev/null +++ b/ext/dsent/model/optical/ThrottledLaserSource.h @@ -0,0 +1,40 @@ +#ifndef __DSENT_MODEL_OPTICAL_THROTTLEDLASERSOURCE_H__ +#define __DSENT_MODEL_OPTICAL_THROTTLEDLASERSOURCE_H__ + +#include "util/CommonType.h" +#include "model/OpticalModel.h" + +namespace DSENT +{ + class OpticalWavelength; + + // A laser source that outputs some number of wavelengths. This laser + // full on/off power gating, thus all power are event-based energies + class ThrottledLaserSource : public OpticalModel + { + public: + ThrottledLaserSource(const String& instance_name_, const TechModel* tech_model_); + virtual ~ThrottledLaserSource(); + + public: + // Set a list of properties' name needed to construct model + void initParameters(); + // Set a list of properties' name needed to construct model + void initProperties(); + + protected: + // Build the model + void constructModel(); + void updateModel(); + void evaluateModel(); + void useModel(); + + private: + // Data structure containing the wavelengths that this laser outputs + OpticalWavelength* m_wavelength_; + + }; // class ThrottledLaserSource +} // namespace DSENT + +#endif // __DSENT_MODEL_OPTICAL_THROTTLEDLASERSOURCE_H__ + diff --git a/ext/dsent/model/optical_graph/OpticalDetector.cc b/ext/dsent/model/optical_graph/OpticalDetector.cc new file mode 100644 index 000000000..8de005099 --- /dev/null +++ b/ext/dsent/model/optical_graph/OpticalDetector.cc @@ -0,0 +1,32 @@ + +#include "model/optical_graph/OpticalDetector.h" +#include "model/optical_graph/OpticalReceiver.h" + +namespace DSENT +{ + OpticalDetector::OpticalDetector(const String& instance_name_, OpticalModel* model_, const WavelengthGroup& wavelengths_, OpticalReceiver* receiver_) + : OpticalNode(OpticalNode::DETECTOR, instance_name_, model_, wavelengths_), m_receiver_(receiver_), m_responsivity_(0) + { + m_sensitivity_ = 0.0; + } + + OpticalDetector::~OpticalDetector() + { + + } + + void OpticalDetector::setResponsivity(double responsivity_) + { + m_responsivity_ = responsivity_; + return; + } + + double OpticalDetector::getSensitivity(double ER_dB_) const + { + // Get responsivity (in Amps) of the receiver, divide by responsivity to get sensitivity in Watts + return m_receiver_->getSensitivity(ER_dB_) / m_responsivity_; + } + +} // namespace DSENT + + diff --git a/ext/dsent/model/optical_graph/OpticalDetector.h b/ext/dsent/model/optical_graph/OpticalDetector.h new file mode 100644 index 000000000..e3994f176 --- /dev/null +++ b/ext/dsent/model/optical_graph/OpticalDetector.h @@ -0,0 +1,45 @@ +#ifndef __DSENT_MODEL_OPTICALGRAPH_OPTICALDETECTOR_H__ +#define __DSENT_MODEL_OPTICALGRAPH_OPTICALDETECTOR_H__ + +#include "model/optical_graph/OpticalNode.h" +#include "util/CommonType.h" + +namespace DSENT +{ + class OpticalReceiver; + + class OpticalDetector : public OpticalNode + { + public: + OpticalDetector(const String& instance_name_, OpticalModel* model_, const WavelengthGroup& wavelengths_, OpticalReceiver* receiver_); + ~OpticalDetector(); + + public: + // Set the responsitivity of the photodetector + void setResponsivity(double responsivity_); + + // Get the detector sensitivity given an extinction ratio (in Watts) + double getSensitivity(double ER_dB_) const; + + // Ask the receiver for its power (ONLY use for power optimization, as this + // assumes an activity of 1.0) + double getPower() const; + + private: + // Disable copy constructor + OpticalDetector(const OpticalDetector& node_); + + private: + // The required laser power + double m_sensitivity_; + // The receiver connected to this detector + OpticalReceiver* m_receiver_; + // Responsivity of the photodetector + double m_responsivity_; + + }; + +} // namespace DSENT + +#endif // __DSENT_MODEL_OPTICALGRAPH_OPTICALDETECTOR_H__ + diff --git a/ext/dsent/model/optical_graph/OpticalFilter.cc b/ext/dsent/model/optical_graph/OpticalFilter.cc new file mode 100644 index 000000000..1bac9a8c9 --- /dev/null +++ b/ext/dsent/model/optical_graph/OpticalFilter.cc @@ -0,0 +1,65 @@ + +#include "model/optical_graph/OpticalFilter.h" + +namespace DSENT +{ + OpticalFilter::OpticalFilter(const String& instance_name_, OpticalModel* model_, const WavelengthGroup& wavelengths_, bool drop_all_, const WavelengthGroup& drop_wavelengths_) + : OpticalNode(OpticalNode::FILTER, instance_name_, model_, wavelengths_), m_drop_all_(drop_all_), m_drop_wavelengths_(drop_wavelengths_) + { + m_drop_loss_ = 0.0; + m_drop_port_ = NULL; + } + + OpticalFilter::~OpticalFilter() + { + + } + + bool OpticalFilter::getDropAll() const + { + return m_drop_all_; + } + + WavelengthGroup OpticalFilter::getDropWavelengths() const + { + return m_drop_wavelengths_; + } + + void OpticalFilter::setDropLoss(double drop_loss_) + { + m_drop_loss_ = drop_loss_; + return; + } + + double OpticalFilter::getDropLoss() const + { + return m_drop_loss_; + } + + void OpticalFilter::setDropPort(OpticalNode* drop_port_) + { + m_drop_port_ = drop_port_; + } + + OpticalNode* OpticalFilter::getDropPort() + { + return m_drop_port_; + } + + bool OpticalFilter::isDropped(const WavelengthGroup& wavelengths_) const + { + // Check that the lower limits are within bounds + bool lower_match = (wavelengths_.first >= getDropWavelengths().first); + // Check that the upper limits are within bounds + bool upper_match = (wavelengths_.second <= getDropWavelengths().second); + // Assert that there are no misalignments + ASSERT(lower_match == upper_match, "[Error] " + getInstanceName() + + " -> Wavelength group misalignment!" + + " InWavelength" + toString(wavelengths_) + + ", DropWavelength" + toString(getDropWavelengths())); + // Both upper and lower bounds must match + return (upper_match && lower_match); + } +} // namespace DSENT + + diff --git a/ext/dsent/model/optical_graph/OpticalFilter.h b/ext/dsent/model/optical_graph/OpticalFilter.h new file mode 100644 index 000000000..e908618e4 --- /dev/null +++ b/ext/dsent/model/optical_graph/OpticalFilter.h @@ -0,0 +1,48 @@ +#ifndef __DSENT_MODEL_OPTICALGRAPH_OPTICALFILTER_H__ +#define __DSENT_MODEL_OPTICALGRAPH_OPTICALFILTER_H__ + +#include "model/optical_graph/OpticalNode.h" +#include "util/CommonType.h" + +namespace DSENT +{ + class OpticalFilter : public OpticalNode + { + public: + OpticalFilter(const String& instance_name_, OpticalModel* model_, const WavelengthGroup& wavelengths_, bool drop_all_, const WavelengthGroup& drop_wavelengths_); + ~OpticalFilter(); + + public: + // Get the drop all flag + bool getDropAll() const; + // Get drop wavelengths + WavelengthGroup getDropWavelengths() const; + // Set and get the drop loss + void setDropLoss(double drop_loss_); + double getDropLoss() const; + // Set and get drop port + void setDropPort(OpticalNode* drop_port_); + OpticalNode* getDropPort(); + // Checks to see if a set of wavelengths will be dropped + bool isDropped(const WavelengthGroup& wavelengths_) const; + + private: + // Disable copy constructor + OpticalFilter(const OpticalFilter& node_); + + private: + // Whether to drop all the optical signal for the drop wavelengths + // i.e. so that the drop wavelengths are not traced anymore + const bool m_drop_all_; + // The loss incurred from in to drop port + double m_drop_loss_; + // The wavelengths that are dropped + const WavelengthGroup m_drop_wavelengths_; + // The node at the drop port + OpticalNode* m_drop_port_; + }; + +} // namespace DSENT + +#endif // __DSENT_MODEL_OPTICALGRAPH_OPTICALFILTER_H__ + diff --git a/ext/dsent/model/optical_graph/OpticalGraph.cc b/ext/dsent/model/optical_graph/OpticalGraph.cc new file mode 100644 index 000000000..424f2bcb2 --- /dev/null +++ b/ext/dsent/model/optical_graph/OpticalGraph.cc @@ -0,0 +1,216 @@ + +#include "model/optical_graph/OpticalGraph.h" + +#include "model/OpticalModel.h" +#include "model/optical_graph/OpticalNode.h" +#include "model/optical_graph/OpticalLaser.h" +#include "model/optical_graph/OpticalModulator.h" +#include "model/optical_graph/OpticalFilter.h" +#include "model/optical_graph/OpticalDetector.h" +#include "model/optical_graph/OpticalWavelength.h" + +namespace DSENT +{ + // Initialize the next visited number to be one above the initial number + // used by OpticalNode + int OpticalGraph::msTreeNum = OpticalNode::OPTICAL_NODE_INIT_VISITED_NUM + 1; + + OpticalGraph::OpticalGraph(const String& instance_name_, OpticalModel* model_) + : m_instance_name_(instance_name_), m_model_(model_) + { + + } + + OpticalGraph::~OpticalGraph() + { + + } + + const String& OpticalGraph::getInstanceName() const + { + return m_instance_name_; + } + + //------------------------------------------------------------------------- + // Perform Datapath power optimization + //------------------------------------------------------------------------- + bool OpticalGraph::performPowerOpt(OpticalNode* node_, const WavelengthGroup& wavelengths_, unsigned int number_detectors_, double util_) + { + // Total number of iterations + unsigned int number_iterations = 1250; + // Maximum IL + ER + double IL_ER_max = 10; + // Figure out the step size used in the sweep + double step = (double) (IL_ER_max / sqrt(2 * number_iterations)); + + // Assume it is possible + bool possible = true; + + // Begin optical data path power optimization + Log::printLine(getInstanceName() + " -> Beginning optical data path power optimization"); + + // Trace the specified wavelengths + OpticalWavelength* wavelength = traceWavelength(wavelengths_, node_); + + // For each data path found in the wavelength + const vector<OpticalDataPath>* data_paths = wavelength->getDataPaths(); + for (unsigned int i = 0; i < data_paths->size(); ++i) + { + const OpticalDataPath& data_path = data_paths->at(i); + // Default to worst possible modulator + double best_power = 1e99; + double best_IL = IL_ER_max - step; + double best_ER = step; + + // Perform power optimization for this data path + Log::printLine(getInstanceName() + " -> Optimize data path - Laser = " + data_path.laser->getInstanceName() + + ", Modulator = " + data_path.modulator->getInstanceName()); + + if (data_path.modulator->canOptimizeLoss()) + { + // Iterate over IL and ER to find optimal set of IL and ER + for (double IL = step; IL < IL_ER_max; IL += step) + { + for (double ER = step; ER <= (IL_ER_max - IL); ER += step) + { + // Ask the modulator to try this new ER and IL + bool success = data_path.modulator->setModulatorSpec(IL, ER); + // If the modulator was successful + if (success) + { + double laser_power = wavelength->getLaserPower(number_detectors_); + double modulator_power = data_path.modulator->getPower(util_); + double total_power = laser_power + modulator_power; + // If this is the new lowest power point + if (total_power < best_power) + { + best_power = total_power; + best_IL = IL; + best_ER = ER; + } + } + } + } + + // Set IL and ER to the best ones we found + bool success = data_path.modulator->setModulatorSpec(best_IL, best_ER); + // If the best one we found was still not possible... + possible = possible && success; + + // Print best IL and ER + Log::printLine(getInstanceName() + " -> Best IL=" + (String) best_IL + ", Best ER=" + (String) best_ER + + ", Best Laser/Mod Power=" + (String) best_power); + } + else + { + // Perform power optimization for this data path + Log::printLine(getInstanceName() + " -> Data path not set to allow optimization"); + } + } + + // End optical data path power optimization + Log::printLine(getInstanceName() + " -> End optical data path power optimization"); + + delete wavelength; + return possible; + } + + + //------------------------------------------------------------------------- + // Trace wavelength(s), returning a wavelength data structure + //------------------------------------------------------------------------- + OpticalWavelength* OpticalGraph::traceWavelength(const WavelengthGroup& wavelengths_, OpticalNode* node_) + { + setTreeNum(getTreeNum() + 1); + OpticalWavelength* wavelength = new OpticalWavelength("TraceWavelength", wavelengths_); + return traceWavelength(wavelength, node_, NULL, NULL, 0.0); + } + + OpticalWavelength* OpticalGraph::traceWavelength(OpticalWavelength* wavelength_, OpticalNode* node_, OpticalLaser* laser_, OpticalModulator* modulator_, double loss_) + { + // If the node has already been visited, don't do anything! + if (node_->getVisitedNum() != getTreeNum()) + { + // Set the new parity for this node + node_->setVisitedNum(getTreeNum()); + + // Calculate the loss of the current path + double current_loss = loss_ + node_->getLoss(); + // Check if the current node is a laser, modulator or detector + if(node_->getType() == OpticalNode::LASER) + { + // Set the laser lighting up the wavelength + ASSERT(laser_ == NULL, "[Error] " + getInstanceName() + " -> Multiple " + + "Lasers lighting up the wavelength!"); + laser_ = (OpticalLaser*) node_; + } + else if (node_->getType() == OpticalNode::MODULATOR) + { + // Check that the path already lit up by a laser and there are no + // modulators already driving data + ASSERT(laser_ != NULL, "[Error] " + getInstanceName() + " -> Wavelength reaches a " + + "modulator (" + node_->getInstanceName() + ") prior to being lit up by a laser!"); + ASSERT(modulator_ == NULL, "[Error] " + getInstanceName() + " -> Two modulators are driving" + + " the same optical data path (" + node_->getInstanceName() + ")!"); + modulator_ = (OpticalModulator*) node_; + } + else if (node_->getType() == OpticalNode::DETECTOR) + { + // Check that the path is both lit up by a laser and there is + // a modulator driving data + ASSERT(laser_ != NULL, "[Error] " + getInstanceName() + " -> Wavelength reaches a " + + "detector (" + node_->getInstanceName() + ") prior to being lit up by a laser!"); + ASSERT(modulator_ != NULL, "[Error] " + getInstanceName() + " -> Wavelength reaches a " + + "detector (" + node_->getInstanceName() + ") prior to being driven by a modulator!"); + // Add a detector to the wavelength + wavelength_->addDataPath(laser_, modulator_, (OpticalDetector*) node_, current_loss); + } + + // Traverse downstream nodes to calculate the delay through each downstream path + vector<OpticalNode*>* d_nodes = node_->getDownstreamNodes(); + bool trace_downstream = (node_->getType() != OpticalNode::DETECTOR); + // Do special things when traversing filters + if (node_->getType() == OpticalNode::FILTER) + { + OpticalFilter* filter_node = (OpticalFilter*) node_; + if (filter_node->isDropped(wavelength_->getWavelengths())) + traceWavelength(wavelength_, filter_node->getDropPort(), laser_, modulator_, loss_ + filter_node->getDropLoss()); + + // If the filter is not modeled as a complete drop, continue tracing downstream + trace_downstream = !filter_node->getDropAll(); + } + + if (trace_downstream) + { + // Trace downstream nodes + for (unsigned int i = 0; i < d_nodes->size(); ++i) + traceWavelength(wavelength_, d_nodes->at(i), laser_, modulator_, current_loss); + } + } + return wavelength_; + } + + //------------------------------------------------------------------------- + OpticalGraph::OpticalGraph(const OpticalGraph& /* graph_ */) + { + // Disabled + } + + OpticalModel* OpticalGraph::getModel() + { + return m_model_; + } + + void OpticalGraph::setTreeNum(int tree_num_) + { + msTreeNum = tree_num_; + return; + } + + int OpticalGraph::getTreeNum() + { + return msTreeNum; + } + +} // namespace DSENT + diff --git a/ext/dsent/model/optical_graph/OpticalGraph.h b/ext/dsent/model/optical_graph/OpticalGraph.h new file mode 100644 index 000000000..43dab1bf8 --- /dev/null +++ b/ext/dsent/model/optical_graph/OpticalGraph.h @@ -0,0 +1,62 @@ +#ifndef __DSENT_MODEL_OPTICALGRAPH_OPTICALGRAPH_H__ +#define __DSENT_MODEL_OPTICALGRAPH_OPTICALGRAPH_H__ + +#include <vector> + +#include "util/CommonType.h" +#include "model/optical_graph/OpticalNode.h" + +namespace DSENT +{ + class OpticalNode; + class OpticalWavelength; + + class OpticalGraph + { + public: + // The visited number for the next timing run. This needs to be + // global because several timing trees may be created to evaluate + // a single timing path, causing problems + static int msTreeNum; + + public: + // Construct timing tree that watches over model_ + OpticalGraph(const String& instance_name_, OpticalModel* model_); + ~OpticalGraph(); + + public: + // Get graph name + const String& getInstanceName() const; + // Perform datapath power optimization by balancing insertion loss and extinction + // ratio with modulator/receiver and laser power, returns false if there are no + // designs that are possible + bool performPowerOpt(OpticalNode* node_, const WavelengthGroup& wavelengths_, unsigned int number_detectors_, double util_); + // Recursively trace a wavelength starting from an OpticalLaser + // source finding all lasers, modulators and detectors that a + // wavelength group hits. + OpticalWavelength* traceWavelength(const WavelengthGroup& wavelengths_, OpticalNode* node_); + OpticalWavelength* traceWavelength(OpticalWavelength* wavelength_, OpticalNode* node_, OpticalLaser* laser_, OpticalModulator* modulator_, double loss_); + // Return the model + OpticalModel* getModel(); + + private: + + // Disable the use of copy constructor + OpticalGraph(const OpticalGraph& graph_); + + public: + // Set the sequence number of the optical graph + static void setTreeNum(int tree_num_); + static int getTreeNum(); + + private: + // Name of the optical graph + const String m_instance_name_; + // A pointer to the model that contains this node + OpticalModel* m_model_; + + }; // class OpticalGraph +} // namespace DSENT + +#endif // __DSENT_MODEL_OPTICALGRAPH_OPTICALGRAPH_H__ + diff --git a/ext/dsent/model/optical_graph/OpticalLaser.cc b/ext/dsent/model/optical_graph/OpticalLaser.cc new file mode 100644 index 000000000..8b25f90bd --- /dev/null +++ b/ext/dsent/model/optical_graph/OpticalLaser.cc @@ -0,0 +1,31 @@ + +#include "model/optical_graph/OpticalLaser.h" + +namespace DSENT +{ + OpticalLaser::OpticalLaser(const String& instance_name_, OpticalModel* model_, const WavelengthGroup& wavelengths_) + : OpticalNode(OpticalNode::LASER, instance_name_, model_, wavelengths_), m_efficiency_(0) + { + + } + + void OpticalLaser::setEfficiency(double efficiency_) + { + m_efficiency_ = efficiency_; + return; + } + + double OpticalLaser::getEfficiency() const + { + return m_efficiency_; + } + + OpticalLaser::~OpticalLaser() + { + + } + + +} // namespace DSENT + + diff --git a/ext/dsent/model/optical_graph/OpticalLaser.h b/ext/dsent/model/optical_graph/OpticalLaser.h new file mode 100644 index 000000000..911517e1d --- /dev/null +++ b/ext/dsent/model/optical_graph/OpticalLaser.h @@ -0,0 +1,32 @@ +#ifndef __DSENT_MODEL_OPTICALGRAPH_OPTICALLASER_H__ +#define __DSENT_MODEL_OPTICALGRAPH_OPTICALLASER_H__ + +#include "model/optical_graph/OpticalNode.h" +#include "util/CommonType.h" + +namespace DSENT +{ + class OpticalLaser : public OpticalNode + { + public: + OpticalLaser(const String& instance_name_, OpticalModel* model_, const WavelengthGroup& wavelengths_); + ~OpticalLaser(); + + public: + void setEfficiency(double efficiency_); + double getEfficiency() const; + + private: + // Disable copy constructor + OpticalLaser(const OpticalLaser& node_); + + private: + // Laser efficiency + double m_efficiency_; + + }; + +} // namespace DSENT + +#endif // __DSENT_MODEL_OPTICALGRAPH_OPTICALLASER_H__ + diff --git a/ext/dsent/model/optical_graph/OpticalModulator.cc b/ext/dsent/model/optical_graph/OpticalModulator.cc new file mode 100644 index 000000000..662560341 --- /dev/null +++ b/ext/dsent/model/optical_graph/OpticalModulator.cc @@ -0,0 +1,54 @@ + +#include "model/optical_graph/OpticalModulator.h" +#include "model/optical_graph/OpticalTransmitter.h" + +namespace DSENT +{ + OpticalModulator::OpticalModulator(const String& instance_name_, OpticalModel* model_, const WavelengthGroup& wavelengths_, bool opt_loss_, OpticalTransmitter* transmitter_) + : OpticalNode(OpticalNode::MODULATOR, instance_name_, model_, wavelengths_), m_transmitter_(transmitter_), m_insertion_loss_(0), m_extinction_ratio_(0), m_opt_loss_(opt_loss_) + { + + } + + OpticalModulator::~OpticalModulator() + { + + } + + bool OpticalModulator::canOptimizeLoss() const + { + return m_opt_loss_; + } + + void OpticalModulator::setLosses(double IL_dB_, double ER_dB_) + { + m_insertion_loss_ = IL_dB_; + m_extinction_ratio_ = ER_dB_; + + return; + } + + bool OpticalModulator::setModulatorSpec(double IL_dB_, double ER_dB_) + { + // Ask the transmitter to design to those specs, returns success or fail + return m_transmitter_->setTransmitterSpec(IL_dB_, ER_dB_); + } + + double OpticalModulator::getPower(double util_) const + { + return m_transmitter_->getPower(util_); + } + + double OpticalModulator::getInsertionLoss() const + { + return m_insertion_loss_; + } + + double OpticalModulator::getExtinctionRatio() const + { + return m_extinction_ratio_; + } + +} // namespace DSENT + + diff --git a/ext/dsent/model/optical_graph/OpticalModulator.h b/ext/dsent/model/optical_graph/OpticalModulator.h new file mode 100644 index 000000000..416c2a0f3 --- /dev/null +++ b/ext/dsent/model/optical_graph/OpticalModulator.h @@ -0,0 +1,51 @@ +#ifndef __DSENT_MODEL_OPTICALGRAPH_OPTICALMODULATOR_H__ +#define __DSENT_MODEL_OPTICALGRAPH_OPTICALMODULATOR_H__ + +#include "model/optical_graph/OpticalNode.h" +#include "util/CommonType.h" + +namespace DSENT +{ + class OpticalTransmitter; + + class OpticalModulator : public OpticalNode + { + public: + OpticalModulator(const String& instance_name_, OpticalModel* model_, const WavelengthGroup& wavelengths_, bool opt_loss_, OpticalTransmitter* transmitter_); + ~OpticalModulator(); + + public: + // Set losses + void setLosses(double IL_dB_, double ER_dB_); + // Tell the modulator to set a new insertion loss and extinction ratio + bool setModulatorSpec(double IL_dB_, double ER_dB_); + // Get modulator insertion loss + double getInsertionLoss() const; + // Get modulator extinction ratio + double getExtinctionRatio() const; + // Ask whether the model is able to optimize for insertion loss + // and extinction ratios + bool canOptimizeLoss() const; + // Ask the modulator for its power at a given utilization + double getPower(double util_) const; + + private: + // Disable copy constructor + OpticalModulator(const OpticalModulator& node_); + + private: + // Optical sender of the modulator + OpticalTransmitter* m_transmitter_; + // Insertion loss of the modulator + double m_insertion_loss_; + // Extinction ratio of the modulator + double m_extinction_ratio_; + // Whether the modulator can be optimized + bool m_opt_loss_; + + }; + +} // namespace DSENT + +#endif // __DSENT_MODEL_OPTICALGRAPH_OPTICALMODULATOR_H__ + diff --git a/ext/dsent/model/optical_graph/OpticalNode.cc b/ext/dsent/model/optical_graph/OpticalNode.cc new file mode 100644 index 000000000..89e034b09 --- /dev/null +++ b/ext/dsent/model/optical_graph/OpticalNode.cc @@ -0,0 +1,96 @@ + +#include "model/optical_graph/OpticalNode.h" + +namespace DSENT +{ + // Set the optical node initial visited num + const int OpticalNode::OPTICAL_NODE_INIT_VISITED_NUM = 0; + + OpticalNode::OpticalNode(Type type_, const String& instance_name_, OpticalModel* model_, const WavelengthGroup& wavelengths_) + :m_type_(type_), m_instance_name_(instance_name_), m_model_(model_), m_wavelengths_(wavelengths_) + { + m_loss_ = 0.0; + setVisitedNum(OpticalNode::OPTICAL_NODE_INIT_VISITED_NUM); + m_downstream_nodes_ = new vector<OpticalNode*>; + } + + OpticalNode::~OpticalNode() + { + + } + + OpticalNode::Type OpticalNode::getType() const + { + return m_type_; + } + + vector<OpticalNode*>* OpticalNode::getDownstreamNodes() const + { + return m_downstream_nodes_; + } + + const String& OpticalNode::getInstanceName() const + { + return m_instance_name_; + } + + OpticalModel* OpticalNode::getModel() + { + return m_model_; + } + + const OpticalModel* OpticalNode::getModel() const + { + return (const OpticalModel*) m_model_; + } + + void OpticalNode::addDownstreamNode(OpticalNode* node_) + { + ASSERT(node_->isExpected(getWavelengths()), "[Error] " + getInstanceName() + + " -> Downstream node not expecting a superset of the current wavelengths"); + m_downstream_nodes_->push_back(node_); + } + + WavelengthGroup OpticalNode::getWavelengths() const + { + return m_wavelengths_; + } + + bool OpticalNode::isExpected(const WavelengthGroup& wavelengths_) const + { + // Check that the lower limits are within bounds + bool lower_match = (wavelengths_.first >= getWavelengths().first); + // Check that the upper limits are within bounds + bool upper_match = (wavelengths_.second <= getWavelengths().second); + // Assert that there are no misalignments + ASSERT(lower_match == upper_match, "[Error] " + getInstanceName() + + " -> Wavelength group misalignment!"); + // Both upper and lower bounds must match + return (upper_match && lower_match); + } + + //------------------------------------------------------------------------- + void OpticalNode::setLoss(double loss_) + { + m_loss_ = loss_; + } + + double OpticalNode::getLoss() const + { + return m_loss_; + } + + void OpticalNode::setVisitedNum(int visited_num_) + { + m_visited_num_ = visited_num_; + } + + int OpticalNode::getVisitedNum() const + { + return m_visited_num_; + } + //------------------------------------------------------------------------- + +} // namespace DSENT + + diff --git a/ext/dsent/model/optical_graph/OpticalNode.h b/ext/dsent/model/optical_graph/OpticalNode.h new file mode 100644 index 000000000..bb88d2da1 --- /dev/null +++ b/ext/dsent/model/optical_graph/OpticalNode.h @@ -0,0 +1,92 @@ +#ifndef __DSENT_MODEL_OPTICALGRAPH_OPTICALNODE_H__ +#define __DSENT_MODEL_OPTICALGRAPH_OPTICALNODE_H__ + +#include "model/OpticalModel.h" +#include "util/CommonType.h" + +namespace DSENT +{ + class OpticalNode; + + //TODO: Change to detector + typedef std::pair<OpticalNode*, double> DetectorEntry; + typedef std::vector<DetectorEntry> DetectorTable; + + class OpticalNode + { + public: + // The starting visited number flag of all optical nodes + static const int OPTICAL_NODE_INIT_VISITED_NUM; + + // The types of optical nodes that can exist + enum Type + { + WAVEGUIDE, + LASER, + MODULATOR, + FILTER, + DETECTOR + }; + + public: + OpticalNode(Type type_, const String& instance_name_, OpticalModel* model_, const WavelengthGroup& wavelengths_); + ~OpticalNode(); + + public: + // Get the type of optical node + Type getType() const; + // Return instance name + const String& getInstanceName() const; + // Get the downstream optical nodes + vector<OpticalNode*>* getDownstreamNodes() const; + // Connect the downstream optical node + void addDownstreamNode(OpticalNode* node_); + // Return the node's parent model + OpticalModel* getModel(); + const OpticalModel* getModel() const; + // Get wavelength groups + WavelengthGroup getWavelengths() const; + // Returns whether the node is expecting a set of wavelengths + bool isExpected(const WavelengthGroup& wavelengths_) const; + + // Trace wavelengths, find and put all found lasers, modulators, and detectors + //virtual void traceWavelengths(const WavelengthGroup& wavelengths_, OpticalNode* laser_, + // OpticalNode* modulator_, DetectorTable* detectors_, double current_loss_) const; + + //----------------------------------------------------------------- + // Node variables for wavelength tracing + //----------------------------------------------------------------- + // Loss incurred at this optical node + void setLoss(double loss_); + double getLoss() const; + // Visited number marker + void setVisitedNum(int visited_num_); + int getVisitedNum() const; + //----------------------------------------------------------------- + + + private: + // Disable copy constructor + OpticalNode(const OpticalNode& node_); + + private: + // The type of optical node + const Type m_type_; + // Name of this instance + String m_instance_name_; + // A pointer to the model that contains this node + OpticalModel* m_model_; + // Downstream optical node + vector<OpticalNode*>* m_downstream_nodes_; + // Path visited count (so that you don't have to clear it) + int m_visited_num_; + // The amount of loss incurred at this optical node + double m_loss_; + // The wavelengths this optical node is supposed to see + const WavelengthGroup m_wavelengths_; + }; + +} // namespace DSENT + +#endif // __DSENT_MODEL_OPTICALGRAPH_OPTICALNODE_H__ + diff --git a/ext/dsent/model/optical_graph/OpticalReceiver.h b/ext/dsent/model/optical_graph/OpticalReceiver.h new file mode 100644 index 000000000..11c940522 --- /dev/null +++ b/ext/dsent/model/optical_graph/OpticalReceiver.h @@ -0,0 +1,25 @@ +#ifndef __DSENT_MODEL_OPTICALGRAPH_OPTICALRECEIVER_H__ +#define __DSENT_MODEL_OPTICALGRAPH_OPTICALRECEIVER_H__ + +#include "model/OpticalModel.h" +#include "util/CommonType.h" + +namespace DSENT +{ + // The job of an optical receiver interface is to provide a function to + // return a sensitivity (in Amps) + class OpticalReceiver + { + public: + OpticalReceiver(){}; + virtual ~OpticalReceiver(){}; + + public: + // Returns the sensitivity of the receiver given an extinction ratio + virtual double getSensitivity(double ER_dB_) const = 0; + }; + +} // namespace DSENT + +#endif // __DSENT_MODEL_OPTICALGRAPH_OPTICALRECEIVER_H__ + diff --git a/ext/dsent/model/optical_graph/OpticalTransmitter.h b/ext/dsent/model/optical_graph/OpticalTransmitter.h new file mode 100644 index 000000000..235d88880 --- /dev/null +++ b/ext/dsent/model/optical_graph/OpticalTransmitter.h @@ -0,0 +1,28 @@ +#ifndef __DSENT_MODEL_OPTICALGRAPH_OPTICALTRANSMITTER_H__ +#define __DSENT_MODEL_OPTICALGRAPH_OPTICALTRANSMITTER_H__ + +#include "model/OpticalModel.h" +#include "util/CommonType.h" + +namespace DSENT +{ + // The job of a optical sender interface is to provide a function to + // allow the insertion loss and extinction ratio to be changed + class OpticalTransmitter + { + public: + OpticalTransmitter(){}; + virtual ~OpticalTransmitter(){}; + + public: + // Set the transmitter specifications, returns whether it is possible + // to build a modulator that met those specs + virtual bool setTransmitterSpec(double IL_dB_, double ER_dB_) = 0; + // Returns power of the transmitter at a given utilization + virtual double getPower(double util_) const = 0; + }; // class OpticalTransmitter + +} // namespace DSENT + +#endif // __DSENT_MODEL_OPTICALGRAPH_OPTICALTRANSMITTER_H__ + diff --git a/ext/dsent/model/optical_graph/OpticalWaveguide.cc b/ext/dsent/model/optical_graph/OpticalWaveguide.cc new file mode 100644 index 000000000..7e35a18aa --- /dev/null +++ b/ext/dsent/model/optical_graph/OpticalWaveguide.cc @@ -0,0 +1,20 @@ + +#include "model/optical_graph/OpticalWaveguide.h" + +namespace DSENT +{ + OpticalWaveguide::OpticalWaveguide(const String& instance_name_, OpticalModel* model_, const WavelengthGroup& wavelengths_) + : OpticalNode(OpticalNode::WAVEGUIDE, instance_name_, model_, wavelengths_) + { + + } + + OpticalWaveguide::~OpticalWaveguide() + { + + } + + +} // namespace DSENT + + diff --git a/ext/dsent/model/optical_graph/OpticalWaveguide.h b/ext/dsent/model/optical_graph/OpticalWaveguide.h new file mode 100644 index 000000000..6fd03bcf3 --- /dev/null +++ b/ext/dsent/model/optical_graph/OpticalWaveguide.h @@ -0,0 +1,27 @@ +#ifndef __DSENT_MODEL_OPTICALGRAPH_OPTICALWAVEGUIDE_H__ +#define __DSENT_MODEL_OPTICALGRAPH_OPTICALWAVEGUIDE_H__ + +#include "model/optical_graph/OpticalNode.h" +#include "util/CommonType.h" + +namespace DSENT +{ + class OpticalWaveguide : public OpticalNode + { + public: + OpticalWaveguide(const String& instance_name_, OpticalModel* model_, const WavelengthGroup& wavelengths_); + ~OpticalWaveguide(); + + public: + // Nothing here... + + private: + // Disable copy constructor + OpticalWaveguide(const OpticalWaveguide& node_); + + }; + +} // namespace DSENT + +#endif // __DSENT_MODEL_OPTICALGRAPH_OPTICALWAVEGUIDE_H__ + diff --git a/ext/dsent/model/optical_graph/OpticalWavelength.cc b/ext/dsent/model/optical_graph/OpticalWavelength.cc new file mode 100644 index 000000000..fa5e36f63 --- /dev/null +++ b/ext/dsent/model/optical_graph/OpticalWavelength.cc @@ -0,0 +1,129 @@ + +#include "model/optical_graph/OpticalWavelength.h" +#include "model/optical_graph/OpticalNode.h" +#include "model/optical_graph/OpticalLaser.h" +#include "model/optical_graph/OpticalModulator.h" +#include "model/optical_graph/OpticalFilter.h" +#include "model/optical_graph/OpticalDetector.h" +#include "model/optical_graph/OpticalWavelength.h" +#include <list> +#include <cmath> + +namespace DSENT +{ + using std::list; + using std::min; + + OpticalWavelength::OpticalWavelength(const String& instance_name_, const WavelengthGroup& wavelengths_) + : m_instance_name_(instance_name_), m_wavelengths_(wavelengths_) + { + m_data_paths_ = new vector<OpticalDataPath>; + } + + OpticalWavelength::~OpticalWavelength() + { + delete m_data_paths_; + } + + const String& OpticalWavelength::getInstanceName() const + { + return m_instance_name_; + } + + void OpticalWavelength::addDataPath(OpticalLaser* laser_, OpticalModulator* modulator_, OpticalDetector* detector_, double loss_) + { + // Expected wavelengths check + ASSERT(laser_->isExpected(getWavelengths()), "[Error] " + getInstanceName() + + " -> " + laser_->getInstanceName() + " is not expecting the set wavelengths!"); + ASSERT(modulator_->isExpected(getWavelengths()), "[Error] " + getInstanceName() + + " -> " + modulator_->getInstanceName() + " is not expecting the set wavelengths!"); + ASSERT(detector_->isExpected(getWavelengths()), "[Error] " + getInstanceName() + + " -> " + detector_->getInstanceName() + " is not expecting the set wavelengths!"); + + // Check to see if the modulator and laser already have a data path entry + bool entry_exists = false; + for (unsigned int i = 0; i < m_data_paths_->size(); ++i) + { + OpticalDataPath& current = m_data_paths_->at(i); + bool current_laser = current.laser == laser_; + bool current_modulator = current.modulator == modulator_; + + ASSERT((current_modulator && current_laser) || !current_modulator, "[Error] " + + getInstanceName() + " -> Modulator is the same, but laser is different?"); + + // If it is already in the table + if (current_modulator) + { + entry_exists = true; + current.detectors.push_back(detector_); + current.losses.push_back(loss_); + } + } + + // If it wasn't found, add the entry + if (!entry_exists) + m_data_paths_->push_back(OpticalDataPath(laser_, modulator_, detector_, loss_)); + return; + } + + const vector<OpticalDataPath>* OpticalWavelength::getDataPaths() const + { + return (const vector<OpticalDataPath>*) m_data_paths_; + } + + WavelengthGroup OpticalWavelength::getWavelengths() const + { + return m_wavelengths_; + } + + double OpticalWavelength::getLaserPower(unsigned int number_detectors_) const + { + ASSERT(number_detectors_ > 0, "[Error] " + getInstanceName() + + " -> Number of detectors must be non-zero!"); + // Find the number of actual wavelengths + int number_wavelengths = getWavelengths().second - getWavelengths().first + 1; + // Laser power sum + double laser_power_sum = 0; + // Loop through all data paths + for (unsigned int i = 0; i < getDataPaths()->size(); ++i) + { + // Get the current data_path + const OpticalDataPath& current_path = getDataPaths()->at(i); + // Create data structure holding the worstcase detectors + list<double>* detectors = new list<double>(); + // Get the extinction ratio of the modulator + double ER_dB = current_path.modulator->getExtinctionRatio(); + // Get the insertion loss of the modulator + double IR_dB = current_path.modulator->getInsertionLoss(); + // Walk through all detectors in a data path + for (unsigned int j = 0; j < current_path.detectors.size(); ++j) + { + // Convert sensitivity, extinction ratio, and path loss to a required laser power + double current_laser_power = current_path.detectors[j]->getSensitivity(ER_dB) * + std::pow(10.0, (current_path.losses[j] + IR_dB) / 10.0) * + 1.0 / (1.0 - pow(10, -ER_dB / 10)); + + // Add the laser power + detectors->push_back(current_laser_power); + } + // Cap the number of detectors + number_detectors_ = std::min(number_detectors_, (unsigned int) current_path.detectors.size()); + // Sort the detectors list in ascending order, only necessary if the number + // of detectors is < total number of detectors + if (number_detectors_ < detectors->size()) + detectors->sort(); + // Sum up the laser power from the worst-case detectors + list<double>::reverse_iterator iter = detectors->rbegin(); + for (unsigned int j = 0; j < number_detectors_; ++j) + { + laser_power_sum += (*iter) / current_path.laser->getEfficiency(); + ++iter; + } + delete detectors; + } + return number_wavelengths * laser_power_sum; + } + +} // namespace DSENT + + diff --git a/ext/dsent/model/optical_graph/OpticalWavelength.h b/ext/dsent/model/optical_graph/OpticalWavelength.h new file mode 100644 index 000000000..6a5f31e9a --- /dev/null +++ b/ext/dsent/model/optical_graph/OpticalWavelength.h @@ -0,0 +1,57 @@ +#ifndef __DSENT_MODEL_OPTICALGRAPH_OPTICALWAVELENGTH_H__ +#define __DSENT_MODEL_OPTICALGRAPH_OPTICALWAVELENGTH_H__ + +#include "model/OpticalModel.h" +#include "util/CommonType.h" + +namespace DSENT +{ + // Optical datapath structure storing a detector table consisting of a + // detector, the loss to that detector, and the modulator driving + // the wavelength for that detector + struct OpticalDataPath + { + OpticalLaser* laser; + OpticalModulator* modulator; + vector<OpticalDetector*> detectors; + vector<double> losses; + + OpticalDataPath(OpticalLaser* laser_, OpticalModulator* modulator_, OpticalDetector* detector_, double loss_) + : laser(laser_), modulator(modulator_), detectors(1, detector_), losses(1, loss_) {} + }; + + class OpticalWavelength + { + // A data structure of a wavelength (or a group of wavelengths). This + // keeps track of all lasers sources, modulators, and detectors that + // the wavelength hits. + public: + OpticalWavelength(const String& instance_name_, const WavelengthGroup& wavelengths_); + ~OpticalWavelength(); + + public: + // Get tree name + const String& getInstanceName() const; + // Get wavelength groups + WavelengthGroup getWavelengths() const; + // Add a datapath for this wavelength + void addDataPath(OpticalLaser* laser_, OpticalModulator* modulator_, OpticalDetector* detector_, double loss_); + const vector<OpticalDataPath>* getDataPaths() const; + // Calculate required wavelength power to reach some number of detectors + // If number_detectors < the number of total detectors this wavelength hits then + // it simply returns the laser power required to reach the worst-case detectors + double getLaserPower(unsigned int number_detectors_) const; + + private: + // Name of the wavelength + const String m_instance_name_; + // Keeps track of the wavelengths + const WavelengthGroup m_wavelengths_; + // Keeps track of a table of laser, detector, modulator mappings + vector<OpticalDataPath>* m_data_paths_; + }; + +} // namespace DSENT + +#endif // __DSENT_MODEL_OPTICALGRAPH_OPTICALWAVEGUIDE_H__ + diff --git a/ext/dsent/model/std_cells/ADDF.cc b/ext/dsent/model/std_cells/ADDF.cc new file mode 100644 index 000000000..99ebcdb6b --- /dev/null +++ b/ext/dsent/model/std_cells/ADDF.cc @@ -0,0 +1,671 @@ +#include "model/std_cells/ADDF.h" + +#include <cmath> + +#include "model/PortInfo.h" +#include "model/EventInfo.h" +#include "model/TransitionInfo.h" +#include "model/std_cells/StdCellLib.h" +#include "model/std_cells/CellMacros.h" +#include "model/timing_graph/ElectricalNet.h" +#include "model/timing_graph/ElectricalDriver.h" +#include "model/timing_graph/ElectricalLoad.h" +#include "model/timing_graph/ElectricalDelay.h" + +namespace DSENT +{ + using std::ceil; + using std::max; + + ADDF::ADDF(const String& instance_name_, const TechModel* tech_model_) + : StdCell(instance_name_, tech_model_) + { + initParameters(); + initProperties(); + } + + ADDF::~ADDF() + {} + + void ADDF::initProperties() + { + return; + } + + void ADDF::constructModel() + { + // All constructModel should do is create Area/NDDPower/Energy Results as + // well as instantiate any sub-instances using only the hard parameters + + createInputPort("A"); + createInputPort("B"); + createInputPort("CI"); + createOutputPort("S"); + createOutputPort("CO"); + + createLoad("A_Cap"); + createLoad("B_Cap"); + createLoad("CI_Cap"); + createDelay("A_to_S_delay"); + createDelay("B_to_S_delay"); + createDelay("CI_to_S_delay"); + createDelay("A_to_CO_delay"); + createDelay("B_to_CO_delay"); + createDelay("CI_to_CO_delay"); + createDriver("S_Ron", true); + createDriver("CO_Ron", true); + + ElectricalLoad* a_cap = getLoad("A_Cap"); + ElectricalLoad* b_cap = getLoad("B_Cap"); + ElectricalLoad* ci_cap = getLoad("CI_Cap"); + ElectricalDelay* a_to_s_delay = getDelay("A_to_S_delay"); + ElectricalDelay* b_to_s_delay = getDelay("B_to_S_delay"); + ElectricalDelay* ci_to_s_delay = getDelay("CI_to_S_delay"); + ElectricalDelay* a_to_co_delay = getDelay("A_to_CO_delay"); + ElectricalDelay* b_to_co_delay = getDelay("B_to_CO_delay"); + ElectricalDelay* ci_to_co_delay = getDelay("CI_to_CO_delay"); + ElectricalDriver* s_ron = getDriver("S_Ron"); + ElectricalDriver* co_ron = getDriver("CO_Ron"); + + getNet("A")->addDownstreamNode(a_cap); + getNet("B")->addDownstreamNode(b_cap); + getNet("CI")->addDownstreamNode(ci_cap); + a_cap->addDownstreamNode(a_to_s_delay); + b_cap->addDownstreamNode(b_to_s_delay); + ci_cap->addDownstreamNode(ci_to_s_delay); + a_cap->addDownstreamNode(a_to_co_delay); + b_cap->addDownstreamNode(b_to_co_delay); + ci_cap->addDownstreamNode(ci_to_co_delay); + + a_to_s_delay->addDownstreamNode(s_ron); + b_to_s_delay->addDownstreamNode(s_ron); + ci_to_s_delay->addDownstreamNode(s_ron); + a_to_co_delay->addDownstreamNode(co_ron); + b_to_co_delay->addDownstreamNode(co_ron); + ci_to_co_delay->addDownstreamNode(co_ron); + + s_ron->addDownstreamNode(getNet("S")); + co_ron->addDownstreamNode(getNet("CO")); + + // Create Area result + // Create NDD Power result + createElectricalAtomicResults(); + // Create ADDF Event Energy Result + createElectricalEventAtomicResult("ADDF"); + + getEventInfo("Idle")->setStaticTransitionInfos(); + + return; + } + + void ADDF::updateModel() + { + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Standard cell cache string + String cell_name = "ADDF_X" + (String) drive_strength; + + // Get timing parameters + getLoad("A_Cap")->setLoadCap(cache->get(cell_name + "->Cap->A")); + getLoad("B_Cap")->setLoadCap(cache->get(cell_name + "->Cap->B")); + getLoad("CI_Cap")->setLoadCap(cache->get(cell_name + "->Cap->CI")); + + getDelay("A_to_S_delay")->setDelay(cache->get(cell_name + "->Delay->A_to_S")); + getDelay("B_to_S_delay")->setDelay(cache->get(cell_name + "->Delay->B_to_S")); + getDelay("CI_to_S_delay")->setDelay(cache->get(cell_name + "->Delay->CI_to_S")); + getDelay("A_to_CO_delay")->setDelay(cache->get(cell_name + "->Delay->A_to_CO")); + getDelay("B_to_CO_delay")->setDelay(cache->get(cell_name + "->Delay->B_to_CO")); + getDelay("CI_to_CO_delay")->setDelay(cache->get(cell_name + "->Delay->CI_to_CO")); + + getDriver("S_Ron")->setOutputRes(cache->get(cell_name + "->DriveRes->S")); + getDriver("CO_Ron")->setOutputRes(cache->get(cell_name + "->DriveRes->CO")); + + // Set the cell area + getAreaResult("Active")->setValue(cache->get(cell_name + "->Area->Active")); + getAreaResult("Metal1Wire")->setValue(cache->get(cell_name + "->Area->Metal1Wire")); + + return; + } + + void ADDF::evaluateModel() + { + return; + } + + void ADDF::useModel() + { + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Standard cell cache string + String cell_name = "ADDF_X" + (String) drive_strength; + + // Propagate the transition info and get the 0->1 transition count + propagateTransitionInfo(); + double P_A = getInputPort("A")->getTransitionInfo().getProbability1(); + double P_B = getInputPort("B")->getTransitionInfo().getProbability1(); + double P_CI = getInputPort("CI")->getTransitionInfo().getProbability1(); + double A_num_trans_01 = getInputPort("A")->getTransitionInfo().getNumberTransitions01(); + double B_num_trans_01 = getInputPort("B")->getTransitionInfo().getNumberTransitions01(); + double CI_num_trans_01 = getInputPort("CI")->getTransitionInfo().getNumberTransitions01(); + double P_num_trans_01 = m_trans_P_.getNumberTransitions01(); + double G_num_trans_01 = m_trans_G_.getNumberTransitions01(); + double CP_num_trans_01 = m_trans_CP_.getNumberTransitions01(); + double S_num_trans_01 = getOutputPort("S")->getTransitionInfo().getNumberTransitions01(); + double CO_num_trans_01 = getOutputPort("CO")->getTransitionInfo().getNumberTransitions01(); + + // Calculate leakage + double leakage = 0; + leakage += cache->get(cell_name + "->Leakage->!A!B!CI") * (1 - P_A) * (1 - P_B) * (1 - P_CI); + leakage += cache->get(cell_name + "->Leakage->!A!BCI") * (1 - P_A) * (1 - P_B) * P_CI; + leakage += cache->get(cell_name + "->Leakage->!AB!CI") * (1 - P_A) * P_B * (1 - P_CI); + leakage += cache->get(cell_name + "->Leakage->!ABCI") * (1 - P_A) * P_B * P_CI; + leakage += cache->get(cell_name + "->Leakage->A!B!CI") * P_A * (1 - P_B) * (1 - P_CI); + leakage += cache->get(cell_name + "->Leakage->A!BCI") * P_A * (1 - P_B) * P_CI; + leakage += cache->get(cell_name + "->Leakage->AB!CI") * P_A * P_B * (1 - P_CI); + leakage += cache->get(cell_name + "->Leakage->ABCI") * P_A * P_B * P_CI; + getNddPowerResult("Leakage")->setValue(leakage); + + // Get VDD + double vdd = getTechModel()->get("Vdd"); + + // Get capacitances + double a_b_cap = cache->get(cell_name + "->Cap->A_b"); + double b_b_cap = cache->get(cell_name + "->Cap->B_b"); + double ci_b_cap = cache->get(cell_name + "->Cap->CI_b"); + double p_cap = cache->get(cell_name + "->Cap->P"); + double p_b_cap = cache->get(cell_name + "->Cap->P_b"); + double s_cap = cache->get(cell_name + "->Cap->S"); + double cp_cap = cache->get(cell_name + "->Cap->CP"); + double g_cap = cache->get(cell_name + "->Cap->G"); + double co_cap = cache->get(cell_name + "->Cap->CO"); + double s_load_cap = getNet("S")->getTotalDownstreamCap(); + double co_load_cap = getNet("CO")->getTotalDownstreamCap(); + + // Calculate ADDF Event energy + double addf_event_energy = 0.0; + addf_event_energy += a_b_cap * A_num_trans_01; + addf_event_energy += b_b_cap * B_num_trans_01; + addf_event_energy += ci_b_cap * CI_num_trans_01; + addf_event_energy += (p_cap + p_b_cap) * P_num_trans_01; + addf_event_energy += (s_cap + s_load_cap) * S_num_trans_01; + addf_event_energy += cp_cap * CP_num_trans_01; + addf_event_energy += g_cap * G_num_trans_01; + addf_event_energy += (co_cap + co_load_cap) * CO_num_trans_01; + addf_event_energy *= vdd * vdd; + getEventResult("ADDF")->setValue(addf_event_energy); + + return; + } + + void ADDF::propagateTransitionInfo() + { + const TransitionInfo& trans_A = getInputPort("A")->getTransitionInfo(); + const TransitionInfo& trans_B = getInputPort("B")->getTransitionInfo(); + const TransitionInfo& trans_CI = getInputPort("CI")->getTransitionInfo(); + + double max_freq_mult = max(max(trans_A.getFrequencyMultiplier(), trans_B.getFrequencyMultiplier()), trans_CI.getFrequencyMultiplier()); + const TransitionInfo& scaled_trans_A = trans_A.scaleFrequencyMultiplier(max_freq_mult); + const TransitionInfo& scaled_trans_B = trans_B.scaleFrequencyMultiplier(max_freq_mult); + const TransitionInfo& scaled_trans_CI = trans_CI.scaleFrequencyMultiplier(max_freq_mult); + + double A_prob_00 = scaled_trans_A.getNumberTransitions00() / max_freq_mult; + double A_prob_01 = scaled_trans_A.getNumberTransitions01() / max_freq_mult; + double A_prob_10 = A_prob_01; + double A_prob_11 = scaled_trans_A.getNumberTransitions11() / max_freq_mult; + double B_prob_00 = scaled_trans_B.getNumberTransitions00() / max_freq_mult; + double B_prob_01 = scaled_trans_B.getNumberTransitions01() / max_freq_mult; + double B_prob_10 = B_prob_01; + double B_prob_11 = scaled_trans_B.getNumberTransitions11() / max_freq_mult; + double CI_prob_00 = scaled_trans_CI.getNumberTransitions00() / max_freq_mult; + double CI_prob_01 = scaled_trans_CI.getNumberTransitions01() / max_freq_mult; + double CI_prob_10 = CI_prob_01; + double CI_prob_11 = scaled_trans_CI.getNumberTransitions11() / max_freq_mult; + + // Set P transition info + double P_prob_00 = A_prob_00 * B_prob_00 + + A_prob_01 * B_prob_01 + + A_prob_10 * B_prob_10 + + A_prob_11 * B_prob_11; + double P_prob_01 = A_prob_00 * B_prob_01 + + A_prob_01 * B_prob_00 + + A_prob_10 * B_prob_11 + + A_prob_11 * B_prob_10; + double P_prob_10 = P_prob_01; + double P_prob_11 = A_prob_00 * B_prob_11 + + A_prob_01 * B_prob_10 + + A_prob_10 * B_prob_01 + + A_prob_11 * B_prob_00; + + // Set G transition info + double G_prob_00 = A_prob_11 * B_prob_11; + double G_prob_01 = A_prob_11 * B_prob_10 + + A_prob_10 * (B_prob_11 + B_prob_10); + double G_prob_10 = G_prob_01; + double G_prob_11 = A_prob_00 + + A_prob_01 * (B_prob_00 + B_prob_10) + + A_prob_10 * (B_prob_00 + B_prob_01) + + A_prob_11 * B_prob_00; + + // Set CP transition info + double CP_prob_00 = P_prob_11 * CI_prob_11; + double CP_prob_01 = P_prob_11 * CI_prob_10 + + P_prob_10 * (CI_prob_11 + CI_prob_10); + double CP_prob_10 = CP_prob_01; + double CP_prob_11 = P_prob_00 + + P_prob_01 * (CI_prob_00 + CI_prob_10) + + P_prob_10 * (CI_prob_00 + CI_prob_01) + + P_prob_11 * CI_prob_00; + + // Set S transition info + double S_prob_00 = P_prob_00 * CI_prob_00 + + P_prob_01 * CI_prob_01 + + P_prob_10 * CI_prob_10 + + P_prob_11 * CI_prob_11; + double S_prob_01 = P_prob_00 * CI_prob_01 + + P_prob_01 * CI_prob_00 + + P_prob_10 * CI_prob_11 + + P_prob_11 * CI_prob_10; + double S_prob_11 = P_prob_00 * CI_prob_11 + + P_prob_01 * CI_prob_10 + + P_prob_10 * CI_prob_01 + + P_prob_11 * CI_prob_00; + + // Set CO transition info + double CO_prob_00 = G_prob_11 * CP_prob_11; + double CO_prob_01 = G_prob_11 * CP_prob_10 + + G_prob_10 * (CP_prob_11 + CP_prob_10); + double CO_prob_11 = G_prob_00 + + G_prob_01 * (CP_prob_00 + CP_prob_10) + + G_prob_10 * (CP_prob_00 + CP_prob_01) + + G_prob_11 * CP_prob_00; + + m_trans_P_ = TransitionInfo(P_prob_00 * max_freq_mult, P_prob_01 * max_freq_mult, P_prob_11 * max_freq_mult); + m_trans_G_ = TransitionInfo(G_prob_00 * max_freq_mult, G_prob_01 * max_freq_mult, G_prob_11 * max_freq_mult); + m_trans_CP_ = TransitionInfo(CP_prob_00 * max_freq_mult, CP_prob_01 * max_freq_mult, CP_prob_11 * max_freq_mult); + + // Check that probabilities add up to 1.0 with some finite tolerance + ASSERT(LibUtil::Math::isEqual((S_prob_00 + S_prob_01 + S_prob_01 + S_prob_11), 1.0), + "[Error] " + getInstanceName() + "Output S transition probabilities must add up to 1 (" + + (String) S_prob_00 + ", " + (String) S_prob_01 + ", " + (String) S_prob_11 + ")!"); + + // Check that probabilities add up to 1.0 with some finite tolerance + ASSERT(LibUtil::Math::isEqual((CO_prob_00 + CO_prob_01 + CO_prob_01 + CO_prob_11), 1.0), + "[Error] " + getInstanceName() + "Output S transition probabilities must add up to 1 (" + + (String) CO_prob_00 + ", " + (String) CO_prob_01 + ", " + (String) CO_prob_11 + ")!"); + + // Turn probability of transitions per cycle into number of transitions per time unit + TransitionInfo trans_S(S_prob_00 * max_freq_mult, S_prob_01 * max_freq_mult, S_prob_11 * max_freq_mult); + getOutputPort("S")->setTransitionInfo(trans_S); + TransitionInfo trans_CO(CO_prob_00 * max_freq_mult, CO_prob_01 * max_freq_mult, CO_prob_11 * max_freq_mult); + getOutputPort("CO")->setTransitionInfo(trans_CO); + return; + } + + // Creates the standard cell, characterizes and abstracts away the details + void ADDF::cacheStdCell(StdCellLib* cell_lib_, double drive_strength_) + { + // Get parameters + double gate_pitch = cell_lib_->getTechModel()->get("Gate->PitchContacted"); + Map<double>* cache = cell_lib_->getStdCellCache(); + + // Standard cell cache string + String cell_name = "ADDF_X" + (String) drive_strength_; + + Log::printLine("=== " + cell_name + " ==="); + + // Now actually build the full standard cell model + createInputPort("A"); + createInputPort("B"); + createInputPort("CI"); + createOutputPort("S"); + createOutputPort("CO"); + + createNet("A_b"); + createNet("B_b"); + createNet("CI_b"); + createNet("P"); + createNet("P_b"); + createNet("G"); //actually G_b since it is NAND'ed + createNet("CP"); //actually (CP)_b since it is NAND'ed + + // Adds macros + CellMacros::addInverter(this, "INV1", false, true, "A", "A_b"); + CellMacros::addInverter(this, "INV2", false, true, "B", "B_b"); + CellMacros::addInverter(this, "INV3", false, true, "CI", "CI_b"); + CellMacros::addInverter(this, "INV4", false, true, "P", "P_b"); + CellMacros::addTristate(this, "INVZ1", false, true, true, true, "B", "A", "A_b", "P"); + CellMacros::addTristate(this, "INVZ2", false, true, true, true, "B_b", "A_b", "A", "P"); + CellMacros::addTristate(this, "INVZ3", true, true, true, true, "P", "CI", "CI_b", "S"); + CellMacros::addTristate(this, "INVZ4", true, true, true, true, "P_b", "CI_b", "CI", "S"); + CellMacros::addNand2(this, "NAND1", false, true, true, "CI", "P", "CP"); + CellMacros::addNand2(this, "NAND2", false, true, true, "A", "B", "G"); + CellMacros::addNand2(this, "NAND3", true, true, true, "CP", "G", "CO"); + + // I have no idea how to size each of the parts haha + CellMacros::updateInverter(this, "INV1", drive_strength_ * 0.250); + CellMacros::updateInverter(this, "INV2", drive_strength_ * 0.250); + CellMacros::updateInverter(this, "INV3", drive_strength_ * 0.250); + CellMacros::updateInverter(this, "INV4", drive_strength_ * 0.500); + CellMacros::updateTristate(this, "INVZ1", drive_strength_ * 0.250); + CellMacros::updateTristate(this, "INVZ2", drive_strength_ * 0.250); + CellMacros::updateTristate(this, "INVZ3", drive_strength_ * 0.500); + CellMacros::updateTristate(this, "INVZ4", drive_strength_ * 0.500); + CellMacros::updateNand2(this, "NAND1", drive_strength_ * 0.500); + CellMacros::updateNand2(this, "NAND2", drive_strength_ * 0.500); + CellMacros::updateNand2(this, "NAND3", drive_strength_ * 1.000); + + // Cache area result + double area = 0.0; + area += gate_pitch * getTotalHeight() * 1; + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV1_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV2_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV3_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV4_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ1_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ2_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ3_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ4_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("NAND1_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("NAND2_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("NAND3_GatePitches").toDouble(); + cache->set(cell_name + "->Area->Active", area); + cache->set(cell_name + "->Area->Metal1Wire", area); + Log::printLine(cell_name + "->Area->Active=" + (String) area); + Log::printLine(cell_name + "->Area->Metal1Wire=" + (String) area); + + // -------------------------------------------------------------------- + // Leakage Model Calculation + // -------------------------------------------------------------------- + // Cache leakage power results (for every single signal combination) + double leakage_000 = 0; //!A, !B, !CI + double leakage_001 = 0; //!A, !B, CI + double leakage_010 = 0; //!A, B, !CI + double leakage_011 = 0; //!A, B, CI + double leakage_100 = 0; //A, !B, !CI + double leakage_101 = 0; //A, !B, CI + double leakage_110 = 0; //A, B, !CI + double leakage_111 = 0; //A, B, CI + + //This is so painful... + leakage_000 += getGenProperties()->get("INV1_LeakagePower_0").toDouble(); + leakage_000 += getGenProperties()->get("INV2_LeakagePower_0").toDouble(); + leakage_000 += getGenProperties()->get("INV3_LeakagePower_0").toDouble(); + leakage_000 += getGenProperties()->get("INV4_LeakagePower_0").toDouble(); + leakage_000 += getGenProperties()->get("INVZ1_LeakagePower_010_0").toDouble(); + leakage_000 += getGenProperties()->get("INVZ2_LeakagePower_101_0").toDouble(); + leakage_000 += getGenProperties()->get("INVZ3_LeakagePower_010_0").toDouble(); + leakage_000 += getGenProperties()->get("INVZ4_LeakagePower_101_0").toDouble(); + leakage_000 += getGenProperties()->get("NAND1_LeakagePower_00").toDouble(); + leakage_000 += getGenProperties()->get("NAND2_LeakagePower_00").toDouble(); + leakage_000 += getGenProperties()->get("NAND3_LeakagePower_11").toDouble(); + + leakage_001 += getGenProperties()->get("INV1_LeakagePower_0").toDouble(); + leakage_001 += getGenProperties()->get("INV2_LeakagePower_0").toDouble(); + leakage_001 += getGenProperties()->get("INV3_LeakagePower_1").toDouble(); + leakage_001 += getGenProperties()->get("INV4_LeakagePower_0").toDouble(); + leakage_001 += getGenProperties()->get("INVZ1_LeakagePower_010_0").toDouble(); + leakage_001 += getGenProperties()->get("INVZ2_LeakagePower_101_0").toDouble(); + leakage_001 += getGenProperties()->get("INVZ3_LeakagePower_100_1").toDouble(); + leakage_001 += getGenProperties()->get("INVZ4_LeakagePower_011_1").toDouble(); + leakage_001 += getGenProperties()->get("NAND1_LeakagePower_10").toDouble(); + leakage_001 += getGenProperties()->get("NAND2_LeakagePower_00").toDouble(); + leakage_001 += getGenProperties()->get("NAND3_LeakagePower_11").toDouble(); + + leakage_010 += getGenProperties()->get("INV1_LeakagePower_0").toDouble(); + leakage_010 += getGenProperties()->get("INV2_LeakagePower_1").toDouble(); + leakage_010 += getGenProperties()->get("INV3_LeakagePower_0").toDouble(); + leakage_010 += getGenProperties()->get("INV4_LeakagePower_1").toDouble(); + leakage_010 += getGenProperties()->get("INVZ1_LeakagePower_011_1").toDouble(); + leakage_010 += getGenProperties()->get("INVZ2_LeakagePower_100_1").toDouble(); + leakage_010 += getGenProperties()->get("INVZ3_LeakagePower_011_1").toDouble(); + leakage_010 += getGenProperties()->get("INVZ4_LeakagePower_100_1").toDouble(); + leakage_010 += getGenProperties()->get("NAND1_LeakagePower_01").toDouble(); + leakage_010 += getGenProperties()->get("NAND2_LeakagePower_01").toDouble(); + leakage_010 += getGenProperties()->get("NAND3_LeakagePower_11").toDouble(); + + leakage_011 += getGenProperties()->get("INV1_LeakagePower_0").toDouble(); + leakage_011 += getGenProperties()->get("INV2_LeakagePower_1").toDouble(); + leakage_011 += getGenProperties()->get("INV3_LeakagePower_1").toDouble(); + leakage_011 += getGenProperties()->get("INV4_LeakagePower_1").toDouble(); + leakage_011 += getGenProperties()->get("INVZ1_LeakagePower_011_1").toDouble(); + leakage_011 += getGenProperties()->get("INVZ2_LeakagePower_100_1").toDouble(); + leakage_011 += getGenProperties()->get("INVZ3_LeakagePower_101_0").toDouble(); + leakage_011 += getGenProperties()->get("INVZ4_LeakagePower_010_0").toDouble(); + leakage_011 += getGenProperties()->get("NAND1_LeakagePower_11").toDouble(); + leakage_011 += getGenProperties()->get("NAND2_LeakagePower_01").toDouble(); + leakage_011 += getGenProperties()->get("NAND3_LeakagePower_01").toDouble(); + + leakage_100 += getGenProperties()->get("INV1_LeakagePower_1").toDouble(); + leakage_100 += getGenProperties()->get("INV2_LeakagePower_0").toDouble(); + leakage_100 += getGenProperties()->get("INV3_LeakagePower_0").toDouble(); + leakage_100 += getGenProperties()->get("INV4_LeakagePower_1").toDouble(); + leakage_100 += getGenProperties()->get("INVZ1_LeakagePower_100_1").toDouble(); + leakage_100 += getGenProperties()->get("INVZ2_LeakagePower_011_1").toDouble(); + leakage_100 += getGenProperties()->get("INVZ3_LeakagePower_011_1").toDouble(); + leakage_100 += getGenProperties()->get("INVZ4_LeakagePower_100_1").toDouble(); + leakage_100 += getGenProperties()->get("NAND1_LeakagePower_01").toDouble(); + leakage_100 += getGenProperties()->get("NAND2_LeakagePower_10").toDouble(); + leakage_100 += getGenProperties()->get("NAND3_LeakagePower_11").toDouble(); + + leakage_101 += getGenProperties()->get("INV1_LeakagePower_1").toDouble(); + leakage_101 += getGenProperties()->get("INV2_LeakagePower_0").toDouble(); + leakage_101 += getGenProperties()->get("INV3_LeakagePower_1").toDouble(); + leakage_101 += getGenProperties()->get("INV4_LeakagePower_1").toDouble(); + leakage_101 += getGenProperties()->get("INVZ1_LeakagePower_100_1").toDouble(); + leakage_101 += getGenProperties()->get("INVZ2_LeakagePower_011_1").toDouble(); + leakage_101 += getGenProperties()->get("INVZ3_LeakagePower_101_0").toDouble(); + leakage_101 += getGenProperties()->get("INVZ4_LeakagePower_010_0").toDouble(); + leakage_101 += getGenProperties()->get("NAND1_LeakagePower_11").toDouble(); + leakage_101 += getGenProperties()->get("NAND2_LeakagePower_10").toDouble(); + leakage_101 += getGenProperties()->get("NAND3_LeakagePower_01").toDouble(); + + leakage_110 += getGenProperties()->get("INV1_LeakagePower_1").toDouble(); + leakage_110 += getGenProperties()->get("INV2_LeakagePower_1").toDouble(); + leakage_110 += getGenProperties()->get("INV3_LeakagePower_0").toDouble(); + leakage_110 += getGenProperties()->get("INV4_LeakagePower_0").toDouble(); + leakage_110 += getGenProperties()->get("INVZ1_LeakagePower_101_0").toDouble(); + leakage_110 += getGenProperties()->get("INVZ2_LeakagePower_010_0").toDouble(); + leakage_110 += getGenProperties()->get("INVZ3_LeakagePower_010_0").toDouble(); + leakage_110 += getGenProperties()->get("INVZ4_LeakagePower_101_0").toDouble(); + leakage_110 += getGenProperties()->get("NAND1_LeakagePower_00").toDouble(); + leakage_110 += getGenProperties()->get("NAND2_LeakagePower_11").toDouble(); + leakage_110 += getGenProperties()->get("NAND3_LeakagePower_10").toDouble(); + + leakage_111 += getGenProperties()->get("INV1_LeakagePower_1").toDouble(); + leakage_111 += getGenProperties()->get("INV2_LeakagePower_1").toDouble(); + leakage_111 += getGenProperties()->get("INV3_LeakagePower_1").toDouble(); + leakage_111 += getGenProperties()->get("INV4_LeakagePower_0").toDouble(); + leakage_111 += getGenProperties()->get("INVZ1_LeakagePower_101_0").toDouble(); + leakage_111 += getGenProperties()->get("INVZ2_LeakagePower_010_0").toDouble(); + leakage_111 += getGenProperties()->get("INVZ3_LeakagePower_100_1").toDouble(); + leakage_111 += getGenProperties()->get("INVZ4_LeakagePower_011_1").toDouble(); + leakage_111 += getGenProperties()->get("NAND1_LeakagePower_10").toDouble(); + leakage_111 += getGenProperties()->get("NAND2_LeakagePower_11").toDouble(); + leakage_111 += getGenProperties()->get("NAND3_LeakagePower_10").toDouble(); + + cache->set(cell_name + "->Leakage->!A!B!CI", leakage_000); + cache->set(cell_name + "->Leakage->!A!BCI", leakage_001); + cache->set(cell_name + "->Leakage->!AB!CI", leakage_010); + cache->set(cell_name + "->Leakage->!ABCI", leakage_011); + cache->set(cell_name + "->Leakage->A!B!CI", leakage_100); + cache->set(cell_name + "->Leakage->A!BCI", leakage_101); + cache->set(cell_name + "->Leakage->AB!CI", leakage_110); + cache->set(cell_name + "->Leakage->ABCI", leakage_111); + Log::printLine(cell_name + "->Leakage->!A!B!CI=" + (String) leakage_000); + Log::printLine(cell_name + "->Leakage->!A!BCI=" + (String) leakage_001); + Log::printLine(cell_name + "->Leakage->!AB!CI=" + (String) leakage_010); + Log::printLine(cell_name + "->Leakage->!ABCI=" + (String) leakage_011); + Log::printLine(cell_name + "->Leakage->A!B!CI=" + (String) leakage_100); + Log::printLine(cell_name + "->Leakage->A!BCI=" + (String) leakage_101); + Log::printLine(cell_name + "->Leakage->AB!CI=" + (String) leakage_110); + Log::printLine(cell_name + "->Leakage->ABCI=" + (String) leakage_111); + // -------------------------------------------------------------------- + + /* + // Cache event energy results + double event_a_flip = 0.0; + event_a_flip += getGenProperties()->get("INV1_A_Flip").toDouble() + getGenProperties()->get("INV1_ZN_Flip").toDouble(); + event_a_flip += getGenProperties()->get("INVZ1_OE_Flip").toDouble() + getGenProperties()->get("INVZ1_OEN_Flip").toDouble(); + event_a_flip += getGenProperties()->get("INVZ2_OE_Flip").toDouble() + getGenProperties()->get("INVZ2_OEN_Flip").toDouble(); + event_a_flip += getGenProperties()->get("NAND2_A1_Flip").toDouble(); + cache->set(cell_name + "->Event_A_Flip", event_a_flip); + Log::printLine(cell_name + "->Event_A_Flip=" + (String) event_a_flip); + + double event_b_flip = 0.0; + event_b_flip += getGenProperties()->get("INV2_A_Flip").toDouble() + getGenProperties()->get("INV2_ZN_Flip").toDouble(); + event_b_flip += getGenProperties()->get("INVZ1_A_Flip").toDouble(); + event_b_flip += getGenProperties()->get("INVZ2_A_Flip").toDouble(); + event_b_flip += getGenProperties()->get("NAND2_A1_Flip").toDouble(); + cache->set(cell_name + "->Event_B_Flip", event_b_flip); + Log::printLine(cell_name + "->Event_B_Flip=" + (String) event_b_flip); + + double event_ci_flip = 0.0; + event_ci_flip += getGenProperties()->get("INV3_A_Flip").toDouble() + getGenProperties()->get("INV3_ZN_Flip").toDouble(); + event_ci_flip += getGenProperties()->get("INVZ3_OE_Flip").toDouble() + getGenProperties()->get("INVZ3_OEN_Flip").toDouble(); + event_ci_flip += getGenProperties()->get("INVZ4_OE_Flip").toDouble() + getGenProperties()->get("INVZ4_OEN_Flip").toDouble(); + event_ci_flip += getGenProperties()->get("NAND1_A1_Flip").toDouble(); + cache->set(cell_name + "->Event_CI_Flip", event_ci_flip); + Log::printLine(cell_name + "->Event_CI_Flip=" + (String) event_ci_flip); + + double event_p_flip = 0.0; + event_p_flip += getGenProperties()->get("INV4_A_Flip").toDouble() + getGenProperties()->get("INV4_ZN_Flip").toDouble(); + event_p_flip += getGenProperties()->get("INVZ1_ZN_Flip").toDouble(); + event_p_flip += getGenProperties()->get("INVZ2_ZN_Flip").toDouble(); + event_p_flip += getGenProperties()->get("NAND1_A2_Flip").toDouble(); + cache->set(cell_name + "->Event_P_Flip", event_p_flip); + Log::printLine(cell_name + "->Event_P_Flip=" + (String) event_p_flip); + + double event_s_flip = 0.0; + event_s_flip += getGenProperties()->get("INVZ3_ZN_Flip").toDouble(); + event_s_flip += getGenProperties()->get("INVZ4_ZN_Flip").toDouble(); + cache->set(cell_name + "->Event_S_Flip", event_s_flip); + Log::printLine(cell_name + "->Event_S_Flip=" + (String) event_s_flip); + + double event_cp_flip = 0.0; + event_cp_flip += getGenProperties()->get("NAND1_ZN_Flip").toDouble(); + event_cp_flip += getGenProperties()->get("NAND3_A2_Flip").toDouble(); + cache->set(cell_name + "->Event_CP_Flip", event_cp_flip); + Log::printLine(cell_name + "->Event_CP_Flip=" + (String) event_cp_flip); + + double event_g_flip = 0.0; + event_g_flip += getGenProperties()->get("NAND2_ZN_Flip").toDouble(); + event_g_flip += getGenProperties()->get("NAND3_A2_Flip").toDouble(); + cache->set(cell_name + "->Event_G_Flip", event_g_flip); + Log::printLine(cell_name + "->Event_G_Flip=" + (String) event_g_flip); + + double event_co_flip = 0.0; + event_co_flip += getGenProperties()->get("NAND3_ZN_Flip").toDouble(); + cache->set(cell_name + "->Event_CO_Flip", event_co_flip); + Log::printLine(cell_name + "->Event_CO_Flip=" + (String) event_co_flip); + */ + // -------------------------------------------------------------------- + // Get Node Capacitances + // -------------------------------------------------------------------- + double a_cap = getNet("A")->getTotalDownstreamCap(); + double b_cap = getNet("B")->getTotalDownstreamCap(); + double ci_cap = getNet("CI")->getTotalDownstreamCap(); + double a_b_cap = getNet("A_b")->getTotalDownstreamCap(); + double b_b_cap = getNet("B_b")->getTotalDownstreamCap(); + double ci_b_cap = getNet("CI_b")->getTotalDownstreamCap(); + double p_cap = getNet("P")->getTotalDownstreamCap(); + double p_b_cap = getNet("P_b")->getTotalDownstreamCap(); + double s_cap = getNet("S")->getTotalDownstreamCap(); + double cp_cap = getNet("CP")->getTotalDownstreamCap(); + double g_cap = getNet("G")->getTotalDownstreamCap(); + double co_cap = getNet("CO")->getTotalDownstreamCap(); + + cache->set(cell_name + "->Cap->A", a_cap); + cache->set(cell_name + "->Cap->B", b_cap); + cache->set(cell_name + "->Cap->CI", ci_cap); + cache->set(cell_name + "->Cap->A_b", a_b_cap); + cache->set(cell_name + "->Cap->B_b", b_b_cap); + cache->set(cell_name + "->Cap->CI_b", ci_b_cap); + cache->set(cell_name + "->Cap->P", p_cap); + cache->set(cell_name + "->Cap->P_b", p_b_cap); + cache->set(cell_name + "->Cap->S", s_cap); + cache->set(cell_name + "->Cap->CP", cp_cap); + cache->set(cell_name + "->Cap->G", g_cap); + cache->set(cell_name + "->Cap->CO", co_cap); + + Log::printLine(cell_name + "->Cap->A=" + (String) a_cap); + Log::printLine(cell_name + "->Cap->B=" + (String) b_cap); + Log::printLine(cell_name + "->Cap->CI=" + (String) ci_cap); + Log::printLine(cell_name + "->Cap->A_b=" + (String) a_b_cap); + Log::printLine(cell_name + "->Cap->B_b=" + (String) b_b_cap); + Log::printLine(cell_name + "->Cap->CI_b=" + (String) ci_b_cap); + Log::printLine(cell_name + "->Cap->P=" + (String) p_cap); + Log::printLine(cell_name + "->Cap->P_b=" + (String) p_b_cap); + Log::printLine(cell_name + "->Cap->S=" + (String) s_cap); + Log::printLine(cell_name + "->Cap->CP=" + (String) cp_cap); + Log::printLine(cell_name + "->Cap->G=" + (String) g_cap); + Log::printLine(cell_name + "->Cap->CO=" + (String) co_cap); + // -------------------------------------------------------------------- + + // -------------------------------------------------------------------- + // Build Internal Delay Model + // -------------------------------------------------------------------- + // Build abstracted timing model + double s_ron = (getDriver("INVZ3_RonZN")->getOutputRes() + getDriver("INVZ4_RonZN")->getOutputRes()) / 2; + double co_ron = getDriver("NAND3_RonZN")->getOutputRes(); + + double a_to_s_delay = 0.0; + a_to_s_delay += getDriver("INV1_RonZN")->calculateDelay(); + a_to_s_delay += max(getDriver("INVZ1_RonZN")->calculateDelay(), getDriver("INVZ2_RonZN")->calculateDelay()); + a_to_s_delay += max(getDriver("INVZ3_RonZN")->calculateDelay(), getDriver("INV4_RonZN")->calculateDelay() + getDriver("INVZ4_RonZN")->calculateDelay()); + + double b_to_s_delay = 0.0; + b_to_s_delay += max(getDriver("INVZ1_RonZN")->calculateDelay(), getDriver("INV2_RonZN")->calculateDelay() + getDriver("INVZ2_RonZN")->calculateDelay()); + b_to_s_delay += max(getDriver("INVZ3_RonZN")->calculateDelay(), getDriver("INV4_RonZN")->calculateDelay() + getDriver("INVZ4_RonZN")->calculateDelay()); + + double ci_to_s_delay = 0.0; + ci_to_s_delay += getDriver("INV3_RonZN")->calculateDelay(); + ci_to_s_delay += max(getDriver("INVZ3_RonZN")->calculateDelay(), getDriver("INVZ4_RonZN")->calculateDelay()); + + double a_to_co_delay = 0.0; + a_to_co_delay += max(getDriver("NAND2_RonZN")->calculateDelay(), //Generate path + getDriver("INV1_RonZN")->calculateDelay() + //Carry propagate path + max(getDriver("INVZ1_RonZN")->calculateDelay(), getDriver("INVZ2_RonZN")->calculateDelay()) + + getDriver("NAND1_RonZN")->calculateDelay()); + a_to_co_delay += getDriver("NAND3_RonZN")->calculateDelay(); + + double b_to_co_delay = 0.0; + b_to_co_delay += max(getDriver("NAND2_RonZN")->calculateDelay(), //Generate path + max(getDriver("INVZ1_RonZN")->calculateDelay(), //Carry propagate path + getDriver("INV2_RonZN")->calculateDelay() + getDriver("INVZ2_RonZN")->calculateDelay()) + + getDriver("NAND1_RonZN")->calculateDelay()); + b_to_co_delay += getDriver("NAND3_RonZN")->calculateDelay(); + + double ci_to_co_delay = 0.0; + ci_to_co_delay += getDriver("NAND1_RonZN")->calculateDelay(); + ci_to_co_delay += getDriver("NAND3_RonZN")->calculateDelay(); + + cache->set(cell_name + "->DriveRes->S", s_ron); + cache->set(cell_name + "->DriveRes->CO", co_ron); + + cache->set(cell_name + "->Delay->A_to_S", a_to_s_delay); + cache->set(cell_name + "->Delay->B_to_S", b_to_s_delay); + cache->set(cell_name + "->Delay->CI_to_S", ci_to_s_delay); + cache->set(cell_name + "->Delay->A_to_CO", a_to_co_delay); + cache->set(cell_name + "->Delay->B_to_CO", b_to_co_delay); + cache->set(cell_name + "->Delay->CI_to_CO", ci_to_co_delay); + + Log::printLine(cell_name + "->DriveRes->S=" + (String) s_ron); + Log::printLine(cell_name + "->DriveRes->CO=" + (String) co_ron); + Log::printLine(cell_name + "->Delay->A_to_S=" + (String) a_to_s_delay); + Log::printLine(cell_name + "->Delay->B_to_S=" + (String) b_to_s_delay); + Log::printLine(cell_name + "->Delay->CI_to_S=" + (String) ci_to_s_delay); + Log::printLine(cell_name + "->Delay->A_to_CO=" + (String) a_to_co_delay); + Log::printLine(cell_name + "->Delay->B_to_CO=" + (String) b_to_co_delay); + Log::printLine(cell_name + "->Delay->CI_to_CO=" + (String) ci_to_co_delay); + // -------------------------------------------------------------------- + + return; + + } + +} // namespace DSENT + diff --git a/ext/dsent/model/std_cells/ADDF.h b/ext/dsent/model/std_cells/ADDF.h new file mode 100644 index 000000000..03bae5d4f --- /dev/null +++ b/ext/dsent/model/std_cells/ADDF.h @@ -0,0 +1,39 @@ +#ifndef __DSENT_MODEL_STD_CELLS_ADDF_H__ +#define __DSENT_MODEL_STD_CELLS_ADDF_H__ + +#include "util/CommonType.h" +#include "model/std_cells/StdCell.h" +#include "model/TransitionInfo.h" + +namespace DSENT +{ + // A full adder standard cell + class ADDF : public StdCell + { + public: + ADDF(const String& instance_name_, const TechModel* tech_model_); + virtual ~ADDF(); + + public: + // Set a list of properties needed to update model + void initProperties(); + // Cache the standard cell + void cacheStdCell(StdCellLib* cell_lib_, double drive_strength_); + private: + TransitionInfo m_trans_P_; + TransitionInfo m_trans_G_; + TransitionInfo m_trans_CP_; + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void evaluateModel(); + virtual void useModel(); + virtual void propagateTransitionInfo(); + + }; // class ADDF +} // namespace DSENT + +#endif // __DSENT_MODEL_STD_CELLS_ADDF_H__ + diff --git a/ext/dsent/model/std_cells/AND2.cc b/ext/dsent/model/std_cells/AND2.cc new file mode 100644 index 000000000..2113c2397 --- /dev/null +++ b/ext/dsent/model/std_cells/AND2.cc @@ -0,0 +1,272 @@ +#include "model/std_cells/AND2.h" + +#include <cmath> + +#include "model/PortInfo.h" +#include "model/TransitionInfo.h" +#include "model/EventInfo.h" +#include "model/std_cells/StdCellLib.h" +#include "model/std_cells/CellMacros.h" +#include "model/timing_graph/ElectricalNet.h" +#include "model/timing_graph/ElectricalDriver.h" +#include "model/timing_graph/ElectricalLoad.h" +#include "model/timing_graph/ElectricalDelay.h" + +namespace DSENT +{ + using std::max; + + AND2::AND2(const String& instance_name_, const TechModel* tech_model_) + : StdCell(instance_name_, tech_model_) + { + initProperties(); + } + + AND2::~AND2() + {} + + void AND2::initProperties() + { + return; + } + + void AND2::constructModel() + { + // All constructModel should do is create Area/NDDPower/Energy Results as + // well as instantiate any sub-instances using only the hard parameters + + createInputPort("A"); + createInputPort("B"); + createOutputPort("Y"); + + createLoad("A_Cap"); + createLoad("B_Cap"); + createDelay("A_to_Y_delay"); + createDelay("B_to_Y_delay"); + createDriver("Y_Ron", true); + + ElectricalLoad* a_cap = getLoad("A_Cap"); + ElectricalLoad* b_cap = getLoad("B_Cap"); + ElectricalDelay* a_to_y_delay = getDelay("A_to_Y_delay"); + ElectricalDelay* b_to_y_delay = getDelay("B_to_Y_delay"); + ElectricalDriver* y_ron = getDriver("Y_Ron"); + + getNet("A")->addDownstreamNode(a_cap); + getNet("B")->addDownstreamNode(b_cap); + a_cap->addDownstreamNode(a_to_y_delay); + b_cap->addDownstreamNode(b_to_y_delay); + a_to_y_delay->addDownstreamNode(y_ron); + b_to_y_delay->addDownstreamNode(y_ron); + y_ron->addDownstreamNode(getNet("Y")); + + // Create Area result + // Create NDD Power result + createElectricalAtomicResults(); + getEventInfo("Idle")->setStaticTransitionInfos(); + // Create AND Event Energy Result + createElectricalEventAtomicResult("AND2"); + + return; + } + + void AND2::updateModel() + { + // All updateModel should do is calculate numbers for the Area/NDDPower/Energy + // Results as anything else that needs to be done using either soft or hard parameters + + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Standard cell cache string + String cell_name = "AND2_X" + (String) drive_strength; + + // Get timing parameters + getLoad("A_Cap")->setLoadCap(cache->get(cell_name + "->Cap->A")); + getLoad("B_Cap")->setLoadCap(cache->get(cell_name + "->Cap->B")); + getDelay("A_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->A_to_Y")); + getDelay("B_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->B_to_Y")); + getDriver("Y_Ron")->setOutputRes(cache->get(cell_name + "->DriveRes->Y")); + + // Set the cell area + getAreaResult("Active")->setValue(cache->get(cell_name + "->ActiveArea")); + getAreaResult("Metal1Wire")->setValue(cache->get(cell_name + "->ActiveArea")); + + return; + } + + void AND2::evaluateModel() + { + return; + } + + void AND2::useModel() + { + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Standard cell cache string + String cell_name = "AND2_X" + (String) drive_strength; + + // Propagate the transition info and get the 0->1 transtion count + propagateTransitionInfo(); + double P_A = getInputPort("A")->getTransitionInfo().getProbability1(); + double P_B = getInputPort("B")->getTransitionInfo().getProbability1(); + double Y_num_trans_01 = getOutputPort("Y")->getTransitionInfo().getNumberTransitions01(); + + // Calculate leakage + double leakage = 0; + leakage += cache->get(cell_name + "->Leakage->!A!B") * (1 - P_A) * (1 - P_B); + leakage += cache->get(cell_name + "->Leakage->!AB") * (1 - P_A) * P_B; + leakage += cache->get(cell_name + "->Leakage->A!B") * P_A * (1 - P_B); + leakage += cache->get(cell_name + "->Leakage->AB") * P_A * P_B; + getNddPowerResult("Leakage")->setValue(leakage); + + // Get VDD + double vdd = getTechModel()->get("Vdd"); + + // Get capacitances + double y_b_cap = cache->get(cell_name + "->Cap->Y_b"); + double y_cap = cache->get(cell_name + "->Cap->Y"); + double y_load_cap = getNet("Y")->getTotalDownstreamCap(); + + // Calculate AND2Event energy + double energy_per_trans_01 = (y_b_cap + y_cap + y_load_cap) * vdd * vdd; + getEventResult("AND2")->setValue(energy_per_trans_01 * Y_num_trans_01); + + return; + } + + void AND2::propagateTransitionInfo() + { + // Get input signal transition info + const TransitionInfo& trans_A = getInputPort("A")->getTransitionInfo(); + const TransitionInfo& trans_B = getInputPort("B")->getTransitionInfo(); + + double max_freq_mult = max(trans_A.getFrequencyMultiplier(), trans_B.getFrequencyMultiplier()); + const TransitionInfo& scaled_trans_A = trans_A.scaleFrequencyMultiplier(max_freq_mult); + const TransitionInfo& scaled_trans_B = trans_B.scaleFrequencyMultiplier(max_freq_mult); + + double A_prob_00 = scaled_trans_A.getNumberTransitions00() / max_freq_mult; + double A_prob_01 = scaled_trans_A.getNumberTransitions01() / max_freq_mult; + double A_prob_10 = A_prob_01; + double A_prob_11 = scaled_trans_A.getNumberTransitions11() / max_freq_mult; + double B_prob_00 = scaled_trans_B.getNumberTransitions00() / max_freq_mult; + double B_prob_01 = scaled_trans_B.getNumberTransitions01() / max_freq_mult; + double B_prob_10 = B_prob_01; + double B_prob_11 = scaled_trans_B.getNumberTransitions11() / max_freq_mult; + + // Set output transition info + double Y_prob_00 = A_prob_00 + + A_prob_01 * (B_prob_00 + B_prob_10) + + A_prob_10 * (B_prob_00 + B_prob_01) + + A_prob_11 * B_prob_00; + double Y_prob_01 = A_prob_01 * (B_prob_01 + B_prob_11) + + A_prob_11 * B_prob_01; + double Y_prob_11 = A_prob_11 * B_prob_11; + + // Check that probabilities add up to 1.0 with some finite tolerance + ASSERT(LibUtil::Math::isEqual(Y_prob_00 + Y_prob_01 + Y_prob_01 + Y_prob_11, 1.0), "[Error] " + getInstanceName() + + "Output transition probabilities must add up to 1 (" + (String) Y_prob_00 + ", " + + (String) Y_prob_01 + ", " + (String) Y_prob_11 + ")!"); + + // Turn probability of transitions per cycle into number of transitions per time unit + TransitionInfo trans_Y(Y_prob_00 * max_freq_mult, Y_prob_01 * max_freq_mult, Y_prob_11 * max_freq_mult); + getOutputPort("Y")->setTransitionInfo(trans_Y); + return; + } + + void AND2::cacheStdCell(StdCellLib* cell_lib_, double drive_strength_) + { + // Standard cell cache string + String cell_name = "AND2_X" + (String) drive_strength_; + + Log::printLine("=== " + cell_name + " ==="); + + // Get parameters + double gate_pitch = cell_lib_->getTechModel()->get("Gate->PitchContacted"); + Map<double>* cache = cell_lib_->getStdCellCache(); + + // Now actually build the full standard cell model + // Create the two input ports + createInputPort("A"); + createInputPort("B"); + createOutputPort("Y"); + + createNet("Y_b"); + + // Adds macros + CellMacros::addNand2(this, "NAND2", false, true, true, "A", "B", "Y_b"); + CellMacros::addInverter(this, "INV", false, true, "Y_b", "Y"); + CellMacros::updateNand2(this, "NAND2", drive_strength_ * 0.5); + CellMacros::updateInverter(this, "INV", drive_strength_ * 1.0); + + // Cache area result + double area = 0.0; + area += gate_pitch * getTotalHeight() * 1; + area += gate_pitch * getTotalHeight() * getGenProperties()->get("NAND2_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV_GatePitches").toDouble(); + cache->set(cell_name + "->ActiveArea", area); + Log::printLine(cell_name + "->ActiveArea=" + (String) area); + + // -------------------------------------------------------------------- + // Leakage Model Calculation + // -------------------------------------------------------------------- + double leakage_00 = getGenProperties()->get("NAND2_LeakagePower_00").toDouble() + + getGenProperties()->get("INV_LeakagePower_0").toDouble(); + double leakage_01 = getGenProperties()->get("NAND2_LeakagePower_01").toDouble() + + getGenProperties()->get("INV_LeakagePower_0").toDouble(); + double leakage_10 = getGenProperties()->get("NAND2_LeakagePower_10").toDouble() + + getGenProperties()->get("INV_LeakagePower_0").toDouble(); + double leakage_11 = getGenProperties()->get("NAND2_LeakagePower_11").toDouble() + + getGenProperties()->get("INV_LeakagePower_1").toDouble(); + cache->set(cell_name + "->Leakage->!A!B", leakage_00); + cache->set(cell_name + "->Leakage->!AB", leakage_01); + cache->set(cell_name + "->Leakage->A!B", leakage_10); + cache->set(cell_name + "->Leakage->AB", leakage_11); + Log::printLine(cell_name + "->Leakage->!A!B=" + (String) leakage_00); + Log::printLine(cell_name + "->Leakage->!AB=" + (String) leakage_01); + Log::printLine(cell_name + "->Leakage->A!B=" + (String) leakage_10); + Log::printLine(cell_name + "->Leakage->AB=" + (String) leakage_11); + // -------------------------------------------------------------------- + + // -------------------------------------------------------------------- + // Get Node Capacitances + // -------------------------------------------------------------------- + double a_cap = getNet("A")->getTotalDownstreamCap(); + double b_cap = getNet("B")->getTotalDownstreamCap(); + double y_b_cap = getNet("Y_b")->getTotalDownstreamCap(); + double y_cap = getNet("Y")->getTotalDownstreamCap(); + + cache->set(cell_name + "->Cap->A", a_cap); + cache->set(cell_name + "->Cap->B", b_cap); + cache->set(cell_name + "->Cap->Y_b", y_b_cap); + cache->set(cell_name + "->Cap->Y", y_cap); + Log::printLine(cell_name + "->Cap->A=" + (String) a_cap); + Log::printLine(cell_name + "->Cap->B=" + (String) b_cap); + Log::printLine(cell_name + "->Cap->Y=" + (String) y_b_cap); + Log::printLine(cell_name + "->Cap->Y=" + (String) y_cap); + // -------------------------------------------------------------------- + + // -------------------------------------------------------------------- + // Build Internal Delay Model + // -------------------------------------------------------------------- + double y_ron = getDriver("INV_RonZN")->getOutputRes(); + double a_to_y_delay = getDriver("NAND2_RonZN")->calculateDelay() + + getDriver("INV_RonZN")->calculateDelay(); + double b_to_y_delay = getDriver("NAND2_RonZN")->calculateDelay() + + getDriver("INV_RonZN")->calculateDelay(); + + cache->set(cell_name + "->DriveRes->Y", y_ron); + cache->set(cell_name + "->Delay->A_to_Y", a_to_y_delay); + cache->set(cell_name + "->Delay->B_to_Y", b_to_y_delay); + Log::printLine(cell_name + "->DriveRes->Y=" + (String) y_ron); + Log::printLine(cell_name + "->Delay->A_to_Y=" + (String) a_to_y_delay); + Log::printLine(cell_name + "->Delay->B_to_Y=" + (String) b_to_y_delay); + // -------------------------------------------------------------------- + + return; + + } +} // namespace DSENT diff --git a/ext/dsent/model/std_cells/AND2.h b/ext/dsent/model/std_cells/AND2.h new file mode 100644 index 000000000..67fe36be1 --- /dev/null +++ b/ext/dsent/model/std_cells/AND2.h @@ -0,0 +1,32 @@ +#ifndef __DSENT_MODEL_STD_CELLS_AND2_H__ +#define __DSENT_MODEL_STD_CELLS_AND2_H__ + +#include "util/CommonType.h" +#include "model/std_cells/StdCell.h" + +namespace DSENT +{ + class AND2 : public StdCell + { + public: + AND2(const String& instance_name_, const TechModel* tech_model_); + virtual ~AND2(); + + public: + // Set a list of properties' name needed to construct model + void initProperties(); + // Cache the standard cell + void cacheStdCell(StdCellLib* cell_lib_, double drive_strength_); + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void evaluateModel(); + virtual void useModel(); + virtual void propagateTransitionInfo(); + }; // class AND2 +} // namespace DSENT + +#endif // __DSENT_MODEL_STD_CELLS_AND2_H__ + diff --git a/ext/dsent/model/std_cells/BUF.cc b/ext/dsent/model/std_cells/BUF.cc new file mode 100644 index 000000000..61c7dac4b --- /dev/null +++ b/ext/dsent/model/std_cells/BUF.cc @@ -0,0 +1,216 @@ +#include "model/std_cells/BUF.h" + +#include <cmath> + +#include "model/PortInfo.h" +#include "model/TransitionInfo.h" +#include "model/EventInfo.h" +#include "model/std_cells/StdCellLib.h" +#include "model/std_cells/CellMacros.h" +#include "model/timing_graph/ElectricalNet.h" +#include "model/timing_graph/ElectricalDriver.h" +#include "model/timing_graph/ElectricalLoad.h" +#include "model/timing_graph/ElectricalDelay.h" + +namespace DSENT +{ + using std::max; + + BUF::BUF(const String& instance_name_, const TechModel* tech_model_) + : StdCell(instance_name_, tech_model_) + { + initProperties(); + } + + BUF::~BUF() + {} + + void BUF::initProperties() + { + return; + } + + void BUF::constructModel() + { + createInputPort("A"); + createOutputPort("Y"); + + createLoad("A_Cap"); + createDelay("A_to_Y_delay"); + createDriver("Y_Ron", true); + + ElectricalLoad* a_cap = getLoad("A_Cap"); + ElectricalDelay* a_to_y_delay = getDelay("A_to_Y_delay"); + ElectricalDriver* y_ron = getDriver("Y_Ron"); + + getNet("A")->addDownstreamNode(a_cap); + a_cap->addDownstreamNode(a_to_y_delay); + a_to_y_delay->addDownstreamNode(y_ron); + y_ron->addDownstreamNode(getNet("Y")); + + // Create Area result + // Create NDD Power result + createElectricalAtomicResults(); + // Create OR Event Energy Result + createElectricalEventAtomicResult("BUF"); + + getEventInfo("Idle")->setStaticTransitionInfos(); + + return; + } + + void BUF::updateModel() + { + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Standard cell cache string + const String& cell_name = "BUF_X" + (String) drive_strength; + + // Get timing parameters + getLoad("A_Cap")->setLoadCap(cache->get(cell_name + "->Cap->A")); + getDelay("A_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->A_to_Y")); + getDriver("Y_Ron")->setOutputRes(cache->get(cell_name + "->DriveRes->Y")); + + // Set the cell area + getAreaResult("Active")->setValue(cache->get(cell_name + "->ActiveArea")); + getAreaResult("Metal1Wire")->setValue(cache->get(cell_name + "->ActiveArea")); + + return; + } + + void BUF::evaluateModel() + { + return; + } + + void BUF::useModel() + { + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Stadard cell cache string + const String& cell_name = "BUF_X" + (String) drive_strength; + + // Propagate the transition info and get the 0->1 transtion count + propagateTransitionInfo(); + double P_A = getInputPort("A")->getTransitionInfo().getProbability1(); + double Y_num_trans_01 = getOutputPort("Y")->getTransitionInfo().getNumberTransitions01(); + + // Calculate leakage + double leakage = 0; + leakage += cache->get(cell_name + "->Leakage->!A") * (1 - P_A); + leakage += cache->get(cell_name + "->Leakage->A") * P_A; + getNddPowerResult("Leakage")->setValue(leakage); + + // Get VDD + double vdd = getTechModel()->get("Vdd"); + + // Get capacitances + double y_b_cap = cache->get(cell_name + "->Cap->Y_b"); + double y_cap = cache->get(cell_name + "->Cap->Y"); + double y_load_cap = getNet("Y")->getTotalDownstreamCap(); + + // Calculate BUFEvent energy + double energy_per_trans_01 = (y_b_cap + y_cap + y_load_cap) * vdd * vdd; + getEventResult("BUF")->setValue(energy_per_trans_01 * Y_num_trans_01); + + return; + } + + void BUF::propagateTransitionInfo() + { + // Get input signal transition info + const TransitionInfo& trans_A = getInputPort("A")->getTransitionInfo(); + + getOutputPort("Y")->setTransitionInfo(trans_A); + return; + } + + // Creates the standard cell, characterizes and abstracts away the details + void BUF::cacheStdCell(StdCellLib* cell_lib_, double drive_strength_) + { + // Get parameters + double gate_pitch = cell_lib_->getTechModel()->get("Gate->PitchContacted"); + Map<double>* cache = cell_lib_->getStdCellCache(); + + // Stadard cell cache string + const String& cell_name = "BUF_X" + (String) drive_strength_; + + Log::printLine("=== " + cell_name + " ==="); + + // Now actually build the full standard cell model + createInputPort("A"); + createOutputPort("Y"); + + createNet("Y_b"); + + // Adds macros + CellMacros::addInverter(this, "INV0", false, true, "A", "Y_b"); + CellMacros::addInverter(this, "INV1", false, true, "Y_b", "Y"); + + // Update macros + CellMacros::updateInverter(this, "INV0", drive_strength_ * 0.367); + CellMacros::updateInverter(this, "INV1", drive_strength_ * 1.0); + + // Cache area result + double area = 0.0; + area += gate_pitch * getTotalHeight() * 1; + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV0_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV1_GatePitches").toDouble(); + cache->set(cell_name + "->ActiveArea", area); + Log::printLine(cell_name + "->ActiveArea=" + (String)area); + + // -------------------------------------------------------------------- + // Leakage Model Calculation + // -------------------------------------------------------------------- + // Cache leakage power results (for every single signal combination) + double leakage_0 = 0.0; // !A + double leakage_1 = 0.0; // A + + leakage_0 += getGenProperties()->get("INV0_LeakagePower_0").toDouble(); + leakage_0 += getGenProperties()->get("INV1_LeakagePower_1").toDouble(); + + leakage_1 += getGenProperties()->get("INV0_LeakagePower_1").toDouble(); + leakage_1 += getGenProperties()->get("INV1_LeakagePower_0").toDouble(); + + cache->set(cell_name + "->Leakage->!A", leakage_0); + cache->set(cell_name + "->Leakage->A", leakage_1); + Log::printLine(cell_name + "->Leakage->!A=" + (String) leakage_0); + Log::printLine(cell_name + "->Leakage->A=" + (String) leakage_1); + // -------------------------------------------------------------------- + + // -------------------------------------------------------------------- + // Get Node Capacitances + // -------------------------------------------------------------------- + double a_cap = getNet("A")->getTotalDownstreamCap(); + double y_b_cap = getNet("Y_b")->getTotalDownstreamCap(); + double y_cap = getNet("Y")->getTotalDownstreamCap(); + + cache->set(cell_name + "->Cap->A", a_cap); + cache->set(cell_name + "->Cap->Y_b", y_b_cap); + cache->set(cell_name + "->Cap->Y", y_cap); + Log::printLine(cell_name + "->Cap->A_Cap=" + (String) a_cap); + Log::printLine(cell_name + "->Cap->Y_b_Cap=" + (String) y_b_cap); + Log::printLine(cell_name + "->Cap->Y_Cap=" + (String) y_cap); + // -------------------------------------------------------------------- + + // -------------------------------------------------------------------- + // Build Internal Delay Model + // -------------------------------------------------------------------- + double y_ron = getDriver("INV1_RonZN")->getOutputRes(); + double a_to_y_delay = getDriver("INV0_RonZN")->calculateDelay() + + getDriver("INV1_RonZN")->calculateDelay(); + + cache->set(cell_name + "->DriveRes->Y", y_ron); + cache->set(cell_name + "->Delay->A_to_Y", a_to_y_delay); + Log::printLine(cell_name + "->DriveRes->Y=" + (String) y_ron); + Log::printLine(cell_name + "->Delay->A_to_Y=" + (String) a_to_y_delay); + // -------------------------------------------------------------------- + + return; + } +} // namespace DSENT + diff --git a/ext/dsent/model/std_cells/BUF.h b/ext/dsent/model/std_cells/BUF.h new file mode 100644 index 000000000..1c85b2a44 --- /dev/null +++ b/ext/dsent/model/std_cells/BUF.h @@ -0,0 +1,33 @@ +#ifndef __DSENT_MODEL_STD_CELLS_BUF_H__ +#define __DSENT_MODEL_STD_CELLS_BUF_H__ + +#include "util/CommonType.h" +#include "model/std_cells/StdCell.h" + +namespace DSENT +{ + class BUF : public StdCell + { + public: + BUF(const String& instance_name_, const TechModel* tech_model_); + virtual ~BUF(); + + public: + // Set a list of properties' name needed to construct model + void initProperties(); + // Cache the standard cell + void cacheStdCell(StdCellLib* cell_lib_, double drive_strength_); + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void evaluateModel(); + virtual void useModel(); + virtual void propagateTransitionInfo(); + + }; // class BUF +} // namespace DSENT + +#endif // __DSENT_MODEL_STD_CELLS_BUF_H__ + diff --git a/ext/dsent/model/std_cells/CellMacros.cc b/ext/dsent/model/std_cells/CellMacros.cc new file mode 100644 index 000000000..5b243942a --- /dev/null +++ b/ext/dsent/model/std_cells/CellMacros.cc @@ -0,0 +1,477 @@ +#include "model/std_cells/CellMacros.h" + +#include <cmath> +#include <vector> + +#include "model/std_cells/StdCell.h" +#include "model/timing_graph/ElectricalNet.h" +#include "model/timing_graph/ElectricalDriver.h" +#include "model/timing_graph/ElectricalLoad.h" + +namespace DSENT +{ + //------------------------------------------------------------------------- + // NOR2 Macro (TODO: Generalize to N-input macro once leakage calc is done) + //------------------------------------------------------------------------- + void CellMacros::addNor2(StdCell* cell_, const String& name_, + bool sizable_, bool a1_to_zn_path_, bool a2_to_zn_path_, + const String& a1_net_, const String& a2_net_, const String& zn_net_) + { + //Create electrical timing model for the nand + // Construct loads and drivers + cell_->createLoad(name_ + "_CgA1"); + cell_->createLoad(name_ + "_CgA2"); + cell_->createLoad(name_ + "_CdZN"); + cell_->createDriver(name_ + "_RonZN", sizable_); + + //Get references to loads and drivers + ElectricalLoad* gate_a1_load = cell_->getLoad(name_ + "_CgA1"); + ElectricalLoad* gate_a2_load = cell_->getLoad(name_ + "_CgA2"); + ElectricalLoad* drain_load = cell_->getLoad(name_ + "_CdZN"); + ElectricalDriver* zn_drive = cell_->getDriver(name_ + "_RonZN"); + ElectricalNet* a1_net = cell_->getNet(a1_net_); + ElectricalNet* a2_net = cell_->getNet(a2_net_); + ElectricalNet* zn_net = cell_->getNet(zn_net_); + + //Add loads and drivers to the specified nets + a1_net->addDownstreamNode(gate_a1_load); + a2_net->addDownstreamNode(gate_a2_load); + zn_net->addDownstreamNode(drain_load); + if (a1_to_zn_path_) gate_a1_load->addDownstreamNode(zn_drive); + if (a2_to_zn_path_) gate_a2_load->addDownstreamNode(zn_drive); + zn_drive->addDownstreamNode(zn_net); + + return; + } + + void CellMacros::updateNor2(StdCell* cell_, const String& name_, double normalized_size_) + { + ASSERT(normalized_size_ >= 0.0, "[Error] " + cell_->getInstanceName() + + " -> Cannot update a macro with a negative normalized size!"); + + //Grab pointer to tech model + const TechModel* tech = cell_->getTechModel(); + + // Get technology parameters + double vdd = tech->get("Vdd"); + double gate_cap = tech->get("Gate->CapPerWidth"); + double drain_cap = tech->get("Drain->CapPerWidth"); + double nmos_eff_res = tech->get("Nmos->EffResWidth"); + double pmos_eff_res = tech->get("Pmos->EffResWidth"); + double pmos_eff_res_stack_ratio = tech->get("Pmos->EffResStackRatio"); + double gate_pitch_contacted = tech->get("Gate->PitchContacted"); + double metal1_wire_min_width = tech->get("Wire->Metal1->MinWidth"); + + //Calculate number of folds and gate pitches needed + unsigned int folds = (normalized_size_ < 1.0) ? 1 : (unsigned int)ceil(normalized_size_); + cell_->getGenProperties()->set(name_ + "_GatePitches", 2 * folds); + + //Calculate widths, making sure they are above the minimum width + double nmos_width = std::max(calculateNmosWidth(cell_, 1, 2, 1) * normalized_size_ / folds, (double) tech->get("Gate->MinWidth")); + double pmos_width = std::max(calculatePmosWidth(cell_, 1, 2, 2) * normalized_size_ / folds, (double) tech->get("Gate->MinWidth")); + + //Calculate leakage power for each given input state + double leakage_power_00 = vdd * folds * 2 * tech->calculateNmosLeakageCurrent(1, nmos_width, 0x0); + double leakage_power_01 = vdd * folds * tech->calculatePmosLeakageCurrent(2, pmos_width, ~0x1); + double leakage_power_10 = vdd * folds * tech->calculatePmosLeakageCurrent(2, pmos_width, ~0x2); + double leakage_power_11 = vdd * folds * tech->calculatePmosLeakageCurrent(2, pmos_width, ~0x3); + cell_->getGenProperties()->set(name_ + "_LeakagePower_00", leakage_power_00); + cell_->getGenProperties()->set(name_ + "_LeakagePower_01", leakage_power_01); + cell_->getGenProperties()->set(name_ + "_LeakagePower_10", leakage_power_10); + cell_->getGenProperties()->set(name_ + "_LeakagePower_11", leakage_power_11); + + //Calculate R_on and capacitances + double pmos_stack2_balance = 1.0 + pmos_eff_res_stack_ratio; + double c_g = (nmos_width + pmos_width) * gate_cap * folds; + double c_d = (2 * pmos_width + 2 * nmos_width) * drain_cap * folds; + double r_on = (nmos_eff_res / nmos_width + pmos_stack2_balance * pmos_eff_res / pmos_width) / (folds * 2.0); + + // Estimate the wire cap and add them all at the output + double cell_height = cell_->getTotalHeight(); + double wire_width = metal1_wire_min_width; + double wire_spacing = gate_pitch_contacted - metal1_wire_min_width; + double wire_length = 2.0 * folds * cell_height; + double wire_cap = tech->calculateWireCapacitance("Metal1", wire_width, wire_spacing, wire_length); + + // Construct equivalent load and drive strength + cell_->getLoad(name_ + "_CgA1")->setLoadCap(c_g); + cell_->getLoad(name_ + "_CgA2")->setLoadCap(c_g); + cell_->getLoad(name_ + "_CdZN")->setLoadCap(c_d + wire_cap); + cell_->getDriver(name_ + "_RonZN")->setOutputRes(r_on); + + // Calculate flip energies + double zn_flip_energy = 0.5 * (c_d + wire_cap) * vdd * vdd; + double a1_flip_energy = 0.5 * c_g * vdd * vdd; + double a2_flip_energy = 0.5 * c_g * vdd * vdd; + cell_->getGenProperties()->set(name_ + "_ZN_Flip", zn_flip_energy); + cell_->getGenProperties()->set(name_ + "_A1_Flip", a1_flip_energy); + cell_->getGenProperties()->set(name_ + "_A2_Flip", a2_flip_energy); + } + //------------------------------------------------------------------------- + + //------------------------------------------------------------------------- + // NAND2 Macro (TODO: Generalize to N-input macro once leakage calc is done) + //------------------------------------------------------------------------- + //Adds a NAND2 to the standard cell, normalized to some size + void CellMacros::addNand2(StdCell* cell_, const String& name_, + bool sizable_, bool a1_to_zn_path_, bool a2_to_zn_path_, + const String& a1_net_, const String& a2_net_, const String& zn_net_) + { + //Create electrical timing model for the nor + // Construct loads and drivers + cell_->createLoad(name_ + "_CgA1"); + cell_->createLoad(name_ + "_CgA2"); + cell_->createLoad(name_ + "_CdZN"); + cell_->createDriver(name_ + "_RonZN", sizable_); + + //Get references to loads and drivers + ElectricalLoad* gate_a1_load = cell_->getLoad(name_ + "_CgA1"); + ElectricalLoad* gate_a2_load = cell_->getLoad(name_ + "_CgA2"); + ElectricalLoad* drain_load = cell_->getLoad(name_ + "_CdZN"); + ElectricalDriver* zn_drive = cell_->getDriver(name_ + "_RonZN"); + ElectricalNet* a1_net = cell_->getNet(a1_net_); + ElectricalNet* a2_net = cell_->getNet(a2_net_); + ElectricalNet* zn_net = cell_->getNet(zn_net_); + + a1_net->addDownstreamNode(gate_a1_load); + a2_net->addDownstreamNode(gate_a2_load); + zn_net->addDownstreamNode(drain_load); + if (a1_to_zn_path_) gate_a1_load->addDownstreamNode(zn_drive); + if (a2_to_zn_path_) gate_a2_load->addDownstreamNode(zn_drive); + zn_drive->addDownstreamNode(zn_net); + + return; + } + + //Updates a NAND2 to to the standard cell, normalized to some size + void CellMacros::updateNand2(StdCell* cell_, const String& name_, double normalized_size_) + { + ASSERT(normalized_size_ >= 0.0, "[Error] " + cell_->getInstanceName() + + " -> Cannot update a macro with a negative normalized size!"); + + //Grab pointer to tech model + const TechModel* tech = cell_->getTechModel(); + + // Get technology parameters + double vdd = tech->get("Vdd"); + double gate_cap = tech->get("Gate->CapPerWidth"); + double drain_cap = tech->get("Drain->CapPerWidth"); + double nmos_eff_res = tech->get("Nmos->EffResWidth"); + double pmos_eff_res = tech->get("Pmos->EffResWidth"); + double nmos_eff_res_stack_ratio = tech->get("Nmos->EffResStackRatio"); + double gate_pitch_contacted = tech->get("Gate->PitchContacted"); + double metal1_wire_min_width = tech->get("Wire->Metal1->MinWidth"); + + //Calculate number of folds needed + unsigned int folds = (normalized_size_ < 1.0) ? 1 : (unsigned int)ceil(normalized_size_); + cell_->getGenProperties()->set(name_ + "_GatePitches", 2 * folds); + + //Calculate widths, making sure they are above the minimum width + double nmos_width = std::max(calculateNmosWidth(cell_, 2, 1, 2) * normalized_size_ / folds, (double) tech->get("Gate->MinWidth")); + double pmos_width = std::max(calculatePmosWidth(cell_, 2, 1, 1) * normalized_size_ / folds, (double) tech->get("Gate->MinWidth")); + + // Leakage power calculation + double leakage_power_00 = vdd * folds * tech->calculateNmosLeakageCurrent(2, nmos_width, 0x0); + double leakage_power_01 = vdd * folds * tech->calculateNmosLeakageCurrent(2, nmos_width, 0x1); + double leakage_power_10 = vdd * folds * tech->calculateNmosLeakageCurrent(2, nmos_width, 0x2); + double leakage_power_11 = vdd * folds * 2 * tech->calculatePmosLeakageCurrent(1, pmos_width, ~0x3); + cell_->getGenProperties()->set(name_ + "_LeakagePower_00", leakage_power_00); + cell_->getGenProperties()->set(name_ + "_LeakagePower_01", leakage_power_01); + cell_->getGenProperties()->set(name_ + "_LeakagePower_10", leakage_power_10); + cell_->getGenProperties()->set(name_ + "_LeakagePower_11", leakage_power_11); + + // Get input parameters + double nmos_stack2_balance = 1.0 + nmos_eff_res_stack_ratio; + + //Calculate caps + double c_g = (nmos_width + pmos_width) * gate_cap * folds; + double c_d = (2 * pmos_width + 2 * nmos_width) * drain_cap * folds; + double r_on = (nmos_stack2_balance * nmos_eff_res / nmos_width + pmos_eff_res / pmos_width) / (folds * 2.0); + + // Estimate the wire cap and add them all at the output + double cell_height = cell_->getTotalHeight(); + double wire_width = metal1_wire_min_width; + double wire_spacing = gate_pitch_contacted - metal1_wire_min_width; + double wire_length = 2.0 * folds * cell_height; + double wire_cap = tech->calculateWireCapacitance("Metal1", wire_width, wire_spacing, wire_length); + + // Construct equivalent load and drive strength + cell_->getLoad(name_ + "_CgA1")->setLoadCap(c_g); + cell_->getLoad(name_ + "_CgA2")->setLoadCap(c_g); + cell_->getLoad(name_ + "_CdZN")->setLoadCap(c_d + wire_cap); + cell_->getDriver(name_ + "_RonZN")->setOutputRes(r_on); + + // Calculate flip energies + double zn_flip_energy = 0.5 * (c_d + wire_cap) * vdd * vdd; + double a1_flip_energy = 0.5 * c_g * vdd * vdd; + double a2_flip_energy = 0.5 * c_g * vdd * vdd; + cell_->getGenProperties()->set(name_ + "_ZN_Flip", zn_flip_energy); + cell_->getGenProperties()->set(name_ + "_A1_Flip", a1_flip_energy); + cell_->getGenProperties()->set(name_ + "_A2_Flip", a2_flip_energy); + } + //------------------------------------------------------------------------- + + //------------------------------------------------------------------------- + // INV Macro + //------------------------------------------------------------------------- + //Adds an inverter to the model, normalized to some size + void CellMacros::addInverter(StdCell* cell_, const String& name_, + bool sizable_, bool a_to_zn_path_, + const String& a_net_, const String& zn_net_) + { + //Create electrical timing model for the inverter + // Construct loads and drivers + cell_->createLoad(name_ + "_CgA"); + cell_->createLoad(name_ + "_CdZN"); + cell_->createDriver(name_ + "_RonZN", sizable_); + + //Get references to loads and drivers + ElectricalLoad* gate_load = cell_->getLoad(name_ + "_CgA"); + ElectricalLoad* drain_load = cell_->getLoad(name_ + "_CdZN"); + ElectricalDriver* out_drive = cell_->getDriver(name_ + "_RonZN"); + ElectricalNet* a_net = cell_->getNet(a_net_); + ElectricalNet* zn_net = cell_->getNet(zn_net_); + + // Setup connectivity of loads and drivers + a_net->addDownstreamNode(gate_load); + if (a_to_zn_path_) gate_load->addDownstreamNode(out_drive); + zn_net->addDownstreamNode(drain_load); + out_drive->addDownstreamNode(zn_net); + + return; + } + + //Updates the numbers of an inverter for some normalized size + void CellMacros::updateInverter(StdCell* cell_, const String& name_, double normalized_size_) + { + ASSERT(normalized_size_ >= 0.0, "[Error] " + cell_->getInstanceName() + + " -> Cannot update a macro with a negative normalized size!"); + + //Grab pointer to tech model + const TechModel* tech = cell_->getTechModel(); + + //Get values from technology library + double vdd = tech->get("Vdd"); + double gate_cap = tech->get("Gate->CapPerWidth"); + double drain_cap = tech->get("Drain->CapPerWidth"); + double nmos_eff_res = tech->get("Nmos->EffResWidth"); + double pmos_eff_res = tech->get("Pmos->EffResWidth"); + double gate_pitch_contacted = tech->get("Gate->PitchContacted"); + double metal1_wire_min_width = tech->get("Wire->Metal1->MinWidth"); + + //Calculate number of folds needed + unsigned int folds = (normalized_size_ < 1.0) ? 1 : (unsigned int)ceil(normalized_size_); + cell_->getGenProperties()->set(name_ + "_GatePitches", folds); + + //Calculate widths, making sure they are above the minimum width + double nmos_width = std::max(calculateNmosWidth(cell_, 1, 1, 1) * normalized_size_ / folds, (double) tech->get("Gate->MinWidth")); + double pmos_width = std::max(calculatePmosWidth(cell_, 1, 1, 1) * normalized_size_ / folds, (double) tech->get("Gate->MinWidth")); + + //Calculate leakage power for each given input state + double leakage_power_0 = vdd * folds * tech->calculateNmosLeakageCurrent(1, nmos_width, 0x0); + double leakage_power_1 = vdd * folds * tech->calculatePmosLeakageCurrent(1, pmos_width, ~0x1); + cell_->getGenProperties()->set(name_ + "_LeakagePower_0", leakage_power_0); + cell_->getGenProperties()->set(name_ + "_LeakagePower_1", leakage_power_1); + + //Calculate caps + double c_g = (nmos_width + pmos_width) * gate_cap * folds; + double c_d = (pmos_width + nmos_width) * drain_cap * folds; + double r_on = (nmos_eff_res / nmos_width + pmos_eff_res / pmos_width) / (folds * 2.0); + + // Estimate the wire cap and add them all at the output + double cell_height = cell_->getTotalHeight(); + double wire_width = metal1_wire_min_width; + double wire_spacing = gate_pitch_contacted - metal1_wire_min_width; + double wire_length = folds * cell_height; + double wire_cap = tech->calculateWireCapacitance("Metal1", wire_width, wire_spacing, wire_length); + + // Construct equivalent load and drive strength + cell_->getLoad(name_ + "_CgA")->setLoadCap(c_g); + cell_->getLoad(name_ + "_CdZN")->setLoadCap(c_d + wire_cap); + cell_->getDriver(name_ + "_RonZN")->setOutputRes(r_on); + + // Calculate flip energy (output flip) + // Calculate flip energies + double zn_flip_energy = 0.5 * (c_d + wire_cap) * vdd * vdd; + double a_flip_energy = 0.5 * c_g * vdd * vdd; + cell_->getGenProperties()->set(name_ + "_ZN_Flip", zn_flip_energy); + cell_->getGenProperties()->set(name_ + "_A_Flip", a_flip_energy); + + return; + } + //------------------------------------------------------------------------- + + //------------------------------------------------------------------------- + // INVZ Macro + //------------------------------------------------------------------------- + //Adds a tristated inverter to the model, normalized to some size + void CellMacros::addTristate(StdCell* cell_, const String& name_, + bool sizable_, bool a_to_zn_path_, bool oe_to_zn_path_, bool oen_to_zn_path_, + const String& a_net_, const String& oe_net_, const String& oen_net_, const String& zn_net_) + { + // Construct loads and drivers + cell_->createLoad(name_ + "_CgA"); + cell_->createLoad(name_ + "_CgOE"); + cell_->createLoad(name_ + "_CgOEN"); + cell_->createLoad(name_ + "_CdZN"); + cell_->createDriver(name_ + "_RonZN", sizable_); + + // Get references to loads, nets and drivers + ElectricalLoad* gate_a_load = cell_->getLoad(name_ + "_CgA"); + ElectricalLoad* gate_oe_load = cell_->getLoad(name_ + "_CgOE"); + ElectricalLoad* gate_oen_load = cell_->getLoad(name_ + "_CgOEN"); + ElectricalLoad* drain_load = cell_->getLoad(name_ + "_CdZN"); + ElectricalDriver* out_drive = cell_->getDriver(name_ + "_RonZN"); + ElectricalNet* a_net = cell_->getNet(a_net_); + ElectricalNet* oe_net = cell_->getNet(oe_net_); + ElectricalNet* oen_net = cell_->getNet(oen_net_); + ElectricalNet* zn_net = cell_->getNet(zn_net_); + + // Setup connectivity of loads and drivers + a_net->addDownstreamNode(gate_a_load); + oe_net->addDownstreamNode(gate_oe_load); + oen_net->addDownstreamNode(gate_oen_load); + if (a_to_zn_path_) gate_a_load->addDownstreamNode(out_drive); + if (oe_to_zn_path_) gate_oe_load->addDownstreamNode(out_drive); + if (oen_to_zn_path_) gate_oen_load->addDownstreamNode(out_drive); + zn_net->addDownstreamNode(drain_load); + out_drive->addDownstreamNode(zn_net); + + return; + } + + //Updates the numbers of an inverter for some normalized size + void CellMacros::updateTristate(StdCell* cell_, const String& name_, double normalized_size_) + { + ASSERT(normalized_size_ >= 0.0, "[Error] " + cell_->getInstanceName() + + " -> Cannot update a macro with a negative normalized size!"); + + //Grab pointer to tech model + const TechModel* tech = cell_->getTechModel(); + + //Get values from technology library + double vdd = tech->get("Vdd"); + double gate_cap = tech->get("Gate->CapPerWidth"); + double drain_cap = tech->get("Drain->CapPerWidth"); + double nmos_eff_res = tech->get("Nmos->EffResWidth"); + double pmos_eff_res = tech->get("Pmos->EffResWidth"); + double pmos_eff_res_stack_ratio = tech->get("Pmos->EffResStackRatio"); + double nmos_eff_res_stack_ratio = tech->get("Nmos->EffResStackRatio"); + double gate_pitch_contacted = tech->get("Gate->PitchContacted"); + double metal1_wire_min_width = tech->get("Wire->Metal1->MinWidth"); + + //Calculate number of folds and gate pitches needed + unsigned int folds = (normalized_size_ < 1.0) ? 1 : (unsigned int)ceil(normalized_size_); + cell_->getGenProperties()->set(name_ + "_GatePitches", 2 * folds); + + //Calculate widths, making sure they are above the minimum width + double nmos_width = std::max(calculateNmosWidth(cell_, 2, 2, 2) * normalized_size_ / folds, (double) tech->get("Gate->MinWidth")); + double pmos_width = std::max(calculatePmosWidth(cell_, 2, 2, 2) * normalized_size_ / folds, (double) tech->get("Gate->MinWidth")); + + //Calculate leakage power for each given input state + //if output_enable = 0, then it is possible that the PMOS may leak (if output = 0), + //or the NMOS will leak (if output = 1) + + //OE OEN A _ ZN + double leakage_power_010_0 = vdd * folds * tech->calculatePmosLeakageCurrent(2, pmos_width, ~0x2); + double leakage_power_010_1 = vdd * folds * tech->calculateNmosLeakageCurrent(2, nmos_width, 0x0); + double leakage_power_011_0 = vdd * folds * tech->calculatePmosLeakageCurrent(2, pmos_width, ~0x3); + double leakage_power_011_1 = vdd * folds * tech->calculateNmosLeakageCurrent(2, nmos_width, 0x1); + double leakage_power_100_1 = vdd * folds * tech->calculateNmosLeakageCurrent(2, nmos_width, 0x2); + double leakage_power_101_0 = vdd * folds * tech->calculatePmosLeakageCurrent(2, pmos_width, ~0x1); + cell_->getGenProperties()->set(name_ + "_LeakagePower_010_0", leakage_power_010_0); + cell_->getGenProperties()->set(name_ + "_LeakagePower_010_1", leakage_power_010_1); + cell_->getGenProperties()->set(name_ + "_LeakagePower_011_0", leakage_power_011_0); + cell_->getGenProperties()->set(name_ + "_LeakagePower_011_1", leakage_power_011_1); + cell_->getGenProperties()->set(name_ + "_LeakagePower_100_1", leakage_power_100_1); + cell_->getGenProperties()->set(name_ + "_LeakagePower_101_0", leakage_power_101_0); + + //Caculate stack balance + double pmos_stack2_balance = 1.0 + pmos_eff_res_stack_ratio; + double nmos_stack2_balance = 1.0 + nmos_eff_res_stack_ratio; + + //Calculate caps + double c_g_a = (nmos_width + pmos_width) * gate_cap * folds; + double c_g_oe = nmos_width * gate_cap * folds; + double c_g_oen = pmos_width * gate_cap * folds; + double c_d = (2 * pmos_width + 2 * nmos_width) * drain_cap * folds; + double r_on = (nmos_stack2_balance * nmos_eff_res / nmos_width + pmos_stack2_balance * pmos_eff_res / pmos_width) / (folds * 2.0); + + // Estimate the wire cap and add them all at the output + double cell_height = cell_->getTotalHeight(); + double wire_width = metal1_wire_min_width; + double wire_spacing = gate_pitch_contacted - metal1_wire_min_width; + double wire_length = 2.0 * folds * cell_height; + double wire_cap = tech->calculateWireCapacitance("Metal1", wire_width, wire_spacing, wire_length); + + // Construct equivalent load and drive strength + cell_->getLoad(name_ + "_CgA")->setLoadCap(c_g_a); + cell_->getLoad(name_ + "_CgOE")->setLoadCap(c_g_oe); + cell_->getLoad(name_ + "_CgOEN")->setLoadCap(c_g_oen); + cell_->getLoad(name_ + "_CdZN")->setLoadCap(c_d + wire_cap); + cell_->getDriver(name_ + "_RonZN")->setOutputRes(r_on); + + // Calculate flip energy (output flip) + double zn_flip_energy = 0.5 * (c_d + wire_cap) * vdd * vdd; + double a_flip_energy = 0.5 * c_g_a * vdd * vdd; + double oe_flip_energy = 0.5 * c_g_oe * vdd * vdd; + double oen_flip_energy = 0.5 * c_g_oen * vdd * vdd; + cell_->getGenProperties()->set(name_ + "_ZN_Flip", zn_flip_energy); + cell_->getGenProperties()->set(name_ + "_A_Flip", a_flip_energy); + cell_->getGenProperties()->set(name_ + "_OE_Flip", oe_flip_energy); + cell_->getGenProperties()->set(name_ + "_OEN_Flip", oen_flip_energy); + return; + } + //------------------------------------------------------------------------- + + + //------------------------------------------------------------------------- + // Helper Functions + //------------------------------------------------------------------------- + //Returns the width of NMOS transistors, given the NMOS and PMOS stacking + double CellMacros::calculateNmosWidth(const StdCell* cell_, unsigned int max_stacked_nmos_, unsigned int max_stacked_pmos_, unsigned int current_stacked_nmos_) + { + //Grab pointer to tech model + const TechModel* tech = cell_->getTechModel(); + + double nmos_eff_res_stack_ratio = tech->get("Nmos->EffResStackRatio"); + double pmos_eff_res_stack_ratio = tech->get("Pmos->EffResStackRatio"); + + double nmos_stack_balance = 1.0 + nmos_eff_res_stack_ratio * (double) (max_stacked_nmos_ - 1); + double pmos_stack_balance = 1.0 + pmos_eff_res_stack_ratio * (double) (max_stacked_pmos_ - 1); + double current_nmos_stack_balance = 1.0 + nmos_eff_res_stack_ratio * (double) (current_stacked_nmos_ - 1); + + double pn_ratio = cell_->getPToNRatio(); + double active_height = cell_->getActiveHeight(); + + //Calculate the width of the current device + double nmos_width = active_height * current_nmos_stack_balance / (nmos_stack_balance + pn_ratio * pmos_stack_balance); + + return nmos_width; + } + + //Returns the width of PMOS transistors, given the NMOS and PMOS stacking + double CellMacros::calculatePmosWidth(const StdCell* cell_, unsigned int max_stacked_nmos_, unsigned int max_stacked_pmos_, unsigned int current_stacked_pmos_) + { + //Grab pointer to tech model + const TechModel* tech = cell_->getTechModel(); + + double nmos_eff_res_stack_ratio = tech->get("Nmos->EffResStackRatio"); + double pmos_eff_res_stack_ratio = tech->get("Pmos->EffResStackRatio"); + + double nmos_stack_balance = 1.0 + nmos_eff_res_stack_ratio * (double) (max_stacked_nmos_ - 1); + double pmos_stack_balance = 1.0 + pmos_eff_res_stack_ratio * (double) (max_stacked_pmos_ - 1); + double current_pmos_stack_balance = 1.0 + pmos_eff_res_stack_ratio * (double) (current_stacked_pmos_ - 1); + + double pn_ratio = cell_->getPToNRatio(); + double active_height = cell_->getActiveHeight(); + + //Calculate the width of the current device + double pmos_width = active_height * current_pmos_stack_balance * pn_ratio / (nmos_stack_balance + pn_ratio * pmos_stack_balance); + + return pmos_width; + } + //------------------------------------------------------------------------- + +} // namespace DSENT + diff --git a/ext/dsent/model/std_cells/CellMacros.h b/ext/dsent/model/std_cells/CellMacros.h new file mode 100644 index 000000000..ce4b54473 --- /dev/null +++ b/ext/dsent/model/std_cells/CellMacros.h @@ -0,0 +1,57 @@ +#ifndef __DSENT_MODEL_STD_CELLS_CELLMACROS_H__ +#define __DSENT_MODEL_STD_CELLS_CELLMACROS_H__ + +#include "util/CommonType.h" +#include "model/std_cells/StdCell.h" + +namespace DSENT +{ + class StdCell; + + // Contains cell macros that can be created within standard cells + class CellMacros + { + private : + CellMacros(); + ~CellMacros(); + + public: + //NOR2 Macro + //Adds a NOR2 to the standard cell, normalized to some size + static void addNor2(StdCell* cell_, const String& name_, bool sizable_, bool a1_to_zn_path_, bool a2_to_zn_path_, + const String& a1_net_, const String& a2_net_, const String& zn_net_); + //Updates a NOR2 to to the standard cell, normalized to some size + static void updateNor2(StdCell* cell_, const String& name_, double normalized_size_); + + //NAND2 Macro + //Adds a NAND2 to the standard cell, normalized to some size + static void addNand2(StdCell* cell_, const String& name_, bool sizable_, bool a1_to_zn_path_, bool a2_to_zn_path_, + const String& a1_net_, const String& a2_net_, const String& zn_net_); + //Updates a NAND2 to to the standard cell, normalized to some size + static void updateNand2(StdCell* cell_, const String& name_, double normalized_size_); + + //INVERTER Macro + //Adds a inverter to the standard cell, normalized to some size + static void addInverter(StdCell* cell_, const String& name_, bool sizable_, bool a_to_zn_path_, + const String& a_net_, const String& zn_net_); + //Updates an inverter to to the standard cell, normalized to some size + static void updateInverter(StdCell* cell_, const String& name_, double normalized_size_); + + //INVZ Macro + //Adds a tristated inverter to the standard cell, normalized to some size + static void addTristate(StdCell* cell_, const String& name_, bool sizable_, bool a_to_zn_path_, bool oe_to_zn_path_, bool oen_to_zn_path_, + const String& a_net_, const String& oe_net_, const String& oen_net_, const String& zn_net_); + //Updates an tristated inverter to to the standard cell, normalized to some size + static void updateTristate(StdCell* cell_, const String& name_, double normalized_size_); + + //Helper functions + //Returns the width of NMOS transistors, given the NMOS and PMOS stacking + static double calculateNmosWidth(const StdCell* cell_, unsigned int max_stacked_nmos_, unsigned int max_stacked_pmos_, unsigned int current_stack_nmos_); + //Returns the width of PMOS transistors, given the NMOS and PMOS stacking + static double calculatePmosWidth(const StdCell* cell_, unsigned int max_stacked_nmos_, unsigned int max_stacked_pmos_, unsigned int current_stack_pmos_); + + }; // class CellMacros +} // namespace DSENT + +#endif // __DSENT_MODEL_STD_CELLS_CELLMACROS_H__ + diff --git a/ext/dsent/model/std_cells/DFFQ.cc b/ext/dsent/model/std_cells/DFFQ.cc new file mode 100644 index 000000000..9080a7211 --- /dev/null +++ b/ext/dsent/model/std_cells/DFFQ.cc @@ -0,0 +1,536 @@ +#include "model/std_cells/DFFQ.h" + +#include <cmath> + +#include "model/PortInfo.h" +#include "model/EventInfo.h" +#include "model/TransitionInfo.h" +#include "model/std_cells/StdCellLib.h" +#include "model/std_cells/CellMacros.h" +#include "model/timing_graph/ElectricalNet.h" +#include "model/timing_graph/ElectricalDriver.h" +#include "model/timing_graph/ElectricalLoad.h" +#include "model/timing_graph/ElectricalDelay.h" + +namespace DSENT +{ + using std::ceil; + using std::max; + using std::min; + + DFFQ::DFFQ(const String& instance_name_, const TechModel* tech_model_) + : StdCell(instance_name_, tech_model_) + { + initProperties(); + } + + DFFQ::~DFFQ() + {} + + void DFFQ::initProperties() + { + return; + } + + void DFFQ::constructModel() + { + // All constructModel should do is create Area/NDDPower/Energy Results as + // well as instantiate any sub-instances using only the hard parameters + + createInputPort("D"); + createInputPort("CK"); + createOutputPort("Q"); + + createLoad("D_Cap"); + createLoad("CK_Cap"); + createDelay("D_Setup_delay"); + createDelay("CK_to_Q_delay"); + createDriver("Q_Ron", true); + + ElectricalLoad* d_cap = getLoad("D_Cap"); + ElectricalLoad* ck_cap = getLoad("CK_Cap"); + ElectricalDelay* d_setup_delay = getDelay("D_Setup_delay"); + ElectricalDelay* ck_to_q_delay = getDelay("CK_to_Q_delay"); + ElectricalDriver* q_ron = getDriver("Q_Ron"); + + getNet("D")->addDownstreamNode(d_cap); + getNet("CK")->addDownstreamNode(ck_cap); + d_cap->addDownstreamNode(d_setup_delay); + ck_cap->addDownstreamNode(ck_to_q_delay); + ck_to_q_delay->addDownstreamNode(q_ron); + q_ron->addDownstreamNode(getNet("Q")); + + // Create Area result + // Create NDD Power result + createElectricalAtomicResults(); + // Create CK Event Energy Result + createElectricalEventAtomicResult("CK"); + getEventInfo("CK")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0)); + // Create DFF Event Energy Result + createElectricalEventAtomicResult("DFFD"); + getEventInfo("DFFD")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0)); + createElectricalEventAtomicResult("DFFQ"); + getEventInfo("DFFQ")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0)); + + // Update Idle event for leakage + // CK pin is assumed to be on all the time + EventInfo* idle_event_info = getEventInfo("Idle"); + idle_event_info->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0)); + idle_event_info->setTransitionInfo("D", TransitionInfo(0.5, 0.0, 0.5)); + + return; + } + + void DFFQ::updateModel() + { + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Standard cell cache string + String cell_name = "DFFQ_X" + (String) drive_strength; + + // Get timing parameters + getLoad("D_Cap")->setLoadCap(cache->get(cell_name + "->Cap->D")); + getLoad("CK_Cap")->setLoadCap(cache->get(cell_name + "->Cap->CK")); + getDriver("Q_Ron")->setOutputRes(cache->get(cell_name + "->DriveRes->Q")); + getDelay("CK_to_Q_delay")->setDelay(cache->get(cell_name + "->Delay->CK_to_Q")); + getDelay("D_Setup_delay")->setDelay(cache->get(cell_name + "->Delay->D_Setup")); + + // Set the cell area + getAreaResult("Active")->setValue(cache->get(cell_name + "->Area->Active")); + getAreaResult("Metal1Wire")->setValue(cache->get(cell_name + "->Area->Metal1Wire")); + + return; + } + + void DFFQ::evaluateModel() + { + return; + } + + void DFFQ::useModel() + { + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Standard cell cache string + String cell_name = "DFFQ_X" + (String) drive_strength; + + // Propagate the transition info and get P_D, P_M, and P_Q + propagateTransitionInfo(); + double P_D = getInputPort("D")->getTransitionInfo().getProbability1(); + double P_CK = getInputPort("CK")->getTransitionInfo().getProbability1(); + double P_Q = getOutputPort("Q")->getTransitionInfo().getProbability1(); + double CK_num_trans_01 = getInputPort("CK")->getTransitionInfo().getNumberTransitions01(); + double D_num_trans_01 = getInputPort("D")->getTransitionInfo().getNumberTransitions01(); + double M_num_trans_01 = m_trans_M_.getNumberTransitions01(); + double Q_num_trans_01 = getOutputPort("Q")->getTransitionInfo().getNumberTransitions01(); + + // Calculate leakage + double leakage = 0; + leakage += cache->get(cell_name + "->Leakage->!D!CK!Q") * (1 - P_D) * (1 - P_CK) * (1 - P_Q); + leakage += cache->get(cell_name + "->Leakage->!D!CKQ") * (1 - P_D) * (1 - P_CK) * P_Q; + leakage += cache->get(cell_name + "->Leakage->!DCK!Q") * (1 - P_D) * P_CK * (1 - P_Q); + leakage += cache->get(cell_name + "->Leakage->!DCKQ") * (1 - P_D) * P_CK * P_Q; + leakage += cache->get(cell_name + "->Leakage->D!CK!Q") * P_D * (1 - P_CK) * (1 - P_Q); + leakage += cache->get(cell_name + "->Leakage->D!CKQ") * P_D * (1 - P_CK) * P_Q; + leakage += cache->get(cell_name + "->Leakage->DCK!Q") * P_D * P_CK * (1 - P_Q); + leakage += cache->get(cell_name + "->Leakage->DCKQ") * P_D * P_CK * P_Q; + getNddPowerResult("Leakage")->setValue(leakage); + + // Get VDD + double vdd = getTechModel()->get("Vdd"); + + // Get capacitances + double ck_b_cap = cache->get(cell_name + "->Cap->CK_b"); + double ck_i_cap = cache->get(cell_name + "->Cap->CK_i"); + double d_b_cap = cache->get(cell_name + "->Cap->D_b"); + double m_b_cap = cache->get(cell_name + "->Cap->M_b"); + double m_cap = cache->get(cell_name + "->Cap->M"); + double m_i_cap = cache->get(cell_name + "->Cap->M_i"); + double q_b_cap = cache->get(cell_name + "->Cap->Q_b"); + double q_cap = cache->get(cell_name + "->Cap->Q"); + double q_load_cap = getNet("Q")->getTotalDownstreamCap(); + + // Calculate CK Event energy + double ck_event_energy = 0.0; + ck_event_energy += (ck_b_cap + ck_i_cap) * CK_num_trans_01; + ck_event_energy *= vdd * vdd; + getEventResult("CK")->setValue(ck_event_energy); + // Calculate DFFD Event energy + double dffd_event_energy = 0.0; + dffd_event_energy += (d_b_cap) * D_num_trans_01; + dffd_event_energy += (m_b_cap + m_cap) * M_num_trans_01; + dffd_event_energy *= vdd * vdd; + getEventResult("DFFD")->setValue(dffd_event_energy); + // Calculate DFFQ Event energy + double dffq_event_energy = 0.0; + dffq_event_energy += (m_i_cap + q_b_cap + q_cap + q_load_cap) * Q_num_trans_01; + dffq_event_energy *= vdd * vdd; + getEventResult("DFFQ")->setValue(dffq_event_energy); + + return; + } + + void DFFQ::propagateTransitionInfo() + { + const TransitionInfo& trans_CK = getInputPort("CK")->getTransitionInfo(); + const TransitionInfo& trans_D = getInputPort("D")->getTransitionInfo(); + + double CK_num_trans_01 = trans_CK.getNumberTransitions01(); + double CK_num_trans_10 = CK_num_trans_01; + double CK_num_trans_00 = trans_CK.getNumberTransitions00(); + double D_freq_mult = trans_D.getFrequencyMultiplier(); + + // If thre is no activity on the clock or D, assume M node is randomly distributed among 0 and 1 + if(LibUtil::Math::isEqual(CK_num_trans_10 + CK_num_trans_00, 0.0) || LibUtil::Math::isEqual(D_freq_mult, 0.0)) + { + m_trans_M_ = TransitionInfo(0.5, 0.0, 0.5); + } + // If the master latch is sampling just as fast or faster than input data signal + // Then it can capture all transitions (though it should be normalized to clock) + else if((CK_num_trans_10 + CK_num_trans_00) >= D_freq_mult) + { + m_trans_M_ = trans_D.scaleFrequencyMultiplier(CK_num_trans_10 + CK_num_trans_00); + } + // If the master latch is sampling slower than the input data signal, then input + // will look like they transition more + else + { + // Calculate scale ratio + double scale_ratio = (CK_num_trans_10 + CK_num_trans_00) / D_freq_mult; + // 00 and 11 transitions become fewer + double D_scaled_diff = 0.5 * (1 - scale_ratio) * (trans_D.getNumberTransitions00() + trans_D.getNumberTransitions11()); + double D_scaled_num_trans_00 = trans_D.getNumberTransitions00() * scale_ratio; + double D_scaled_num_trans_11 = trans_D.getNumberTransitions11() * scale_ratio; + // 01 and 10 transitions become more frequent + double D_scaled_num_trans_10 = trans_D.getNumberTransitions01() + D_scaled_diff; + + // Create final transition info, remembering to apply scaling ratio to normalize to CK + m_trans_M_ = TransitionInfo(D_scaled_num_trans_00 * scale_ratio, + D_scaled_num_trans_10 * scale_ratio, + D_scaled_num_trans_11 * scale_ratio); + } + + // If the clock activity is 0 or if D activity is 0, then we assume that the output is randomly distributed among 0 and 1 + if(LibUtil::Math::isEqual(CK_num_trans_01, 0.0) || LibUtil::Math::isEqual(D_freq_mult, 0.0)) + { + getOutputPort("Q")->setTransitionInfo(TransitionInfo(0.5, 0.0, 0.5)); + } + // If the DFF's CK is running at a higher frequency than D, Q is just D with a + // scaled up frequency multiplier + else if(CK_num_trans_01 >= D_freq_mult) + { + const TransitionInfo& trans_Q = trans_D.scaleFrequencyMultiplier(CK_num_trans_01); + getOutputPort("Q")->setTransitionInfo(trans_Q); + } + // If the DFF is sampling slower than the input data signal, then inputs + // will look like they transition more + else + { + // Calculate scale ratio + double scale_ratio = CK_num_trans_01 / D_freq_mult; + // 00 and 11 transitions become fewer + double D_scaled_diff = 0.5 * (1 - scale_ratio) * (trans_D.getNumberTransitions00() + trans_D.getNumberTransitions11()); + double D_scaled_num_trans_00 = trans_D.getNumberTransitions00() * scale_ratio; + double D_scaled_num_trans_11 = trans_D.getNumberTransitions11() * scale_ratio; + // 01 and 10 transitions become more frequent + double D_scaled_num_trans_10 = trans_D.getNumberTransitions01() + D_scaled_diff; + const TransitionInfo trans_Q( D_scaled_num_trans_00 * scale_ratio, + D_scaled_num_trans_10 * scale_ratio, + D_scaled_num_trans_11 * scale_ratio); + getOutputPort("Q")->setTransitionInfo(trans_Q); + } + return; + } + + // Creates the standard cell, characterizes and abstracts away the details + void DFFQ::cacheStdCell(StdCellLib* cell_lib_, double drive_strength_) + { + // Get parameters + double gate_pitch = cell_lib_->getTechModel()->get("Gate->PitchContacted"); + Map<double>* cache = cell_lib_->getStdCellCache(); + + // Standard cell cache string + String cell_name = "DFFQ_X" + (String) drive_strength_; + + Log::printLine("=== " + cell_name + " ==="); + + + // Now actually build the full standard cell model + createInputPort("D"); + createInputPort("CK"); + createOutputPort("Q"); + + createNet("D_b"); + createNet("M_b"); + createNet("M"); + createNet("M_i"); + createNet("Q_b"); + createNet("CK_b"); + createNet("CK_i"); + + // Adds macros + CellMacros::addInverter(this, "INV1", false, true, "D", "D_b"); + CellMacros::addInverter(this, "INV2", false, true, "M_b", "M"); + CellMacros::addInverter(this, "INV3", false, true, "M_i", "Q_b"); + CellMacros::addInverter(this, "INV4", true, true, "Q_b", "Q"); + CellMacros::addInverter(this, "INV5", false, true, "CK", "CK_b"); + CellMacros::addInverter(this, "INV6", false, true, "CK_b", "CK_i"); + CellMacros::addTristate(this, "INVZ1", false, true, false, false, "D_b", "CK_b", "CK_i", "M_b"); //trace timing through A->ZN path only + CellMacros::addTristate(this, "INVZ2", false, false, false, false, "M", "CK_i", "CK_b", "M_b"); //don't trace timing through the feedback path + CellMacros::addTristate(this, "INVZ3", false, false, true, true, "M", "CK_i", "CK_b", "M_i"); //trace timing from OE->ZN and OEN->ZN paths only + CellMacros::addTristate(this, "INVZ4", false, false, false, false, "Q_b", "CK_b", "CK_i", "M_i"); //don't trace timing through the feedback path + + // Update macros + CellMacros::updateInverter(this, "INV1", drive_strength_ * 0.125); + CellMacros::updateInverter(this, "INV2", drive_strength_ * 0.5); + CellMacros::updateInverter(this, "INV3", drive_strength_ * 0.5); + CellMacros::updateInverter(this, "INV4", drive_strength_ * 1.0); + CellMacros::updateInverter(this, "INV5", drive_strength_ * 0.125); + CellMacros::updateInverter(this, "INV6", drive_strength_ * 0.125); + CellMacros::updateTristate(this, "INVZ1", drive_strength_ * 0.5); + CellMacros::updateTristate(this, "INVZ2", drive_strength_ * 0.0625); + CellMacros::updateTristate(this, "INVZ3", drive_strength_ * 0.5); + CellMacros::updateTristate(this, "INVZ4", drive_strength_ * 0.0625); + + // Cache area result + double area = 0.0; + area += gate_pitch * getTotalHeight() * 1; + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV1_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV2_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV3_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV4_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV5_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV6_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ1_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ2_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ3_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ4_GatePitches").toDouble(); + cache->set(cell_name + "->Area->Active", area); + cache->set(cell_name + "->Area->Metal1Wire", area); + Log::printLine(cell_name + "->Area->Active=" + (String) area); + Log::printLine(cell_name + "->Area->Metal1Wire=" + (String) area); + + // -------------------------------------------------------------------- + // Leakage Model Calculation + // -------------------------------------------------------------------- + // Cache leakage power results (for every single signal combination) + double leakage_000 = 0; //!D, !CK, !Q + double leakage_001 = 0; //!D, !CK, Q + double leakage_010 = 0; //!D, CK, !Q + double leakage_011 = 0; //!D, CK, Q + double leakage_100 = 0; //D, !CK, !Q + double leakage_101 = 0; //D, !CK, Q + double leakage_110 = 0; //D, CK, !Q + double leakage_111 = 0; //D, CK, Q + + //This is so painful... + leakage_000 += getGenProperties()->get("INV1_LeakagePower_0").toDouble(); + leakage_000 += getGenProperties()->get("INV2_LeakagePower_0").toDouble(); + leakage_000 += getGenProperties()->get("INV3_LeakagePower_0").toDouble(); + leakage_000 += getGenProperties()->get("INV4_LeakagePower_1").toDouble(); + leakage_000 += getGenProperties()->get("INV5_LeakagePower_0").toDouble(); + leakage_000 += getGenProperties()->get("INV6_LeakagePower_1").toDouble(); + leakage_000 += getGenProperties()->get("INVZ1_LeakagePower_101_0").toDouble(); + leakage_000 += getGenProperties()->get("INVZ2_LeakagePower_011_0").toDouble(); + leakage_000 += getGenProperties()->get("INVZ3_LeakagePower_011_0").toDouble(); + leakage_000 += getGenProperties()->get("INVZ4_LeakagePower_101_0").toDouble(); + + leakage_001 += getGenProperties()->get("INV1_LeakagePower_0").toDouble(); + leakage_001 += getGenProperties()->get("INV2_LeakagePower_0").toDouble(); + leakage_001 += getGenProperties()->get("INV3_LeakagePower_1").toDouble(); + leakage_001 += getGenProperties()->get("INV4_LeakagePower_0").toDouble(); + leakage_001 += getGenProperties()->get("INV5_LeakagePower_0").toDouble(); + leakage_001 += getGenProperties()->get("INV6_LeakagePower_1").toDouble(); + leakage_001 += getGenProperties()->get("INVZ1_LeakagePower_101_0").toDouble(); + leakage_001 += getGenProperties()->get("INVZ2_LeakagePower_011_0").toDouble(); + leakage_001 += getGenProperties()->get("INVZ3_LeakagePower_011_1").toDouble(); + leakage_001 += getGenProperties()->get("INVZ4_LeakagePower_100_1").toDouble(); + + leakage_010 += getGenProperties()->get("INV1_LeakagePower_0").toDouble(); + leakage_010 += getGenProperties()->get("INV2_LeakagePower_0").toDouble(); + leakage_010 += getGenProperties()->get("INV3_LeakagePower_0").toDouble(); + leakage_010 += getGenProperties()->get("INV4_LeakagePower_1").toDouble(); + leakage_010 += getGenProperties()->get("INV5_LeakagePower_1").toDouble(); + leakage_010 += getGenProperties()->get("INV6_LeakagePower_0").toDouble(); + leakage_010 += getGenProperties()->get("INVZ1_LeakagePower_011_0").toDouble(); + leakage_010 += getGenProperties()->get("INVZ2_LeakagePower_101_0").toDouble(); + leakage_010 += getGenProperties()->get("INVZ3_LeakagePower_101_0").toDouble(); + leakage_010 += getGenProperties()->get("INVZ4_LeakagePower_011_0").toDouble(); + + leakage_011 += getGenProperties()->get("INV1_LeakagePower_0").toDouble(); + leakage_011 += getGenProperties()->get("INV2_LeakagePower_1").toDouble(); + leakage_011 += getGenProperties()->get("INV3_LeakagePower_1").toDouble(); + leakage_011 += getGenProperties()->get("INV4_LeakagePower_0").toDouble(); + leakage_011 += getGenProperties()->get("INV5_LeakagePower_1").toDouble(); + leakage_011 += getGenProperties()->get("INV6_LeakagePower_0").toDouble(); + leakage_011 += getGenProperties()->get("INVZ1_LeakagePower_011_1").toDouble(); + leakage_011 += getGenProperties()->get("INVZ2_LeakagePower_100_1").toDouble(); + leakage_011 += getGenProperties()->get("INVZ3_LeakagePower_100_1").toDouble(); + leakage_011 += getGenProperties()->get("INVZ4_LeakagePower_010_1").toDouble(); + + leakage_100 += getGenProperties()->get("INV1_LeakagePower_1").toDouble(); + leakage_100 += getGenProperties()->get("INV2_LeakagePower_1").toDouble(); + leakage_100 += getGenProperties()->get("INV3_LeakagePower_0").toDouble(); + leakage_100 += getGenProperties()->get("INV4_LeakagePower_1").toDouble(); + leakage_100 += getGenProperties()->get("INV5_LeakagePower_0").toDouble(); + leakage_100 += getGenProperties()->get("INV6_LeakagePower_1").toDouble(); + leakage_100 += getGenProperties()->get("INVZ1_LeakagePower_100_1").toDouble(); + leakage_100 += getGenProperties()->get("INVZ2_LeakagePower_010_1").toDouble(); + leakage_100 += getGenProperties()->get("INVZ3_LeakagePower_010_0").toDouble(); + leakage_100 += getGenProperties()->get("INVZ4_LeakagePower_101_0").toDouble(); + + leakage_101 += getGenProperties()->get("INV1_LeakagePower_1").toDouble(); + leakage_101 += getGenProperties()->get("INV2_LeakagePower_1").toDouble(); + leakage_101 += getGenProperties()->get("INV3_LeakagePower_1").toDouble(); + leakage_101 += getGenProperties()->get("INV4_LeakagePower_0").toDouble(); + leakage_101 += getGenProperties()->get("INV5_LeakagePower_0").toDouble(); + leakage_101 += getGenProperties()->get("INV6_LeakagePower_1").toDouble(); + leakage_101 += getGenProperties()->get("INVZ1_LeakagePower_100_1").toDouble(); + leakage_101 += getGenProperties()->get("INVZ2_LeakagePower_010_1").toDouble(); + leakage_101 += getGenProperties()->get("INVZ3_LeakagePower_010_1").toDouble(); + leakage_101 += getGenProperties()->get("INVZ4_LeakagePower_100_1").toDouble(); + + leakage_110 += getGenProperties()->get("INV1_LeakagePower_1").toDouble(); + leakage_110 += getGenProperties()->get("INV2_LeakagePower_0").toDouble(); + leakage_110 += getGenProperties()->get("INV3_LeakagePower_0").toDouble(); + leakage_110 += getGenProperties()->get("INV4_LeakagePower_1").toDouble(); + leakage_110 += getGenProperties()->get("INV5_LeakagePower_1").toDouble(); + leakage_110 += getGenProperties()->get("INV6_LeakagePower_0").toDouble(); + leakage_110 += getGenProperties()->get("INVZ1_LeakagePower_010_0").toDouble(); + leakage_110 += getGenProperties()->get("INVZ2_LeakagePower_101_0").toDouble(); + leakage_110 += getGenProperties()->get("INVZ3_LeakagePower_101_0").toDouble(); + leakage_110 += getGenProperties()->get("INVZ4_LeakagePower_011_0").toDouble(); + + leakage_111 += getGenProperties()->get("INV1_LeakagePower_1").toDouble(); + leakage_111 += getGenProperties()->get("INV2_LeakagePower_1").toDouble(); + leakage_111 += getGenProperties()->get("INV3_LeakagePower_1").toDouble(); + leakage_111 += getGenProperties()->get("INV4_LeakagePower_0").toDouble(); + leakage_111 += getGenProperties()->get("INV5_LeakagePower_1").toDouble(); + leakage_111 += getGenProperties()->get("INV6_LeakagePower_0").toDouble(); + leakage_111 += getGenProperties()->get("INVZ1_LeakagePower_010_1").toDouble(); + leakage_111 += getGenProperties()->get("INVZ2_LeakagePower_100_1").toDouble(); + leakage_111 += getGenProperties()->get("INVZ3_LeakagePower_100_1").toDouble(); + leakage_111 += getGenProperties()->get("INVZ4_LeakagePower_010_1").toDouble(); + + cache->set(cell_name + "->Leakage->!D!CK!Q", leakage_000); + cache->set(cell_name + "->Leakage->!D!CKQ", leakage_001); + cache->set(cell_name + "->Leakage->!DCK!Q", leakage_010); + cache->set(cell_name + "->Leakage->!DCKQ", leakage_011); + cache->set(cell_name + "->Leakage->D!CK!Q", leakage_100); + cache->set(cell_name + "->Leakage->D!CKQ", leakage_101); + cache->set(cell_name + "->Leakage->DCK!Q", leakage_110); + cache->set(cell_name + "->Leakage->DCKQ", leakage_111); + Log::printLine(cell_name + "->Leakage->!D!CK!Q=" + (String) leakage_000); + Log::printLine(cell_name + "->Leakage->!D!CKQ=" + (String) leakage_001); + Log::printLine(cell_name + "->Leakage->!DCK!Q=" + (String) leakage_010); + Log::printLine(cell_name + "->Leakage->!DCKQ=" + (String) leakage_011); + Log::printLine(cell_name + "->Leakage->D!CK!Q=" + (String) leakage_100); + Log::printLine(cell_name + "->Leakage->D!CKQ=" + (String) leakage_101); + Log::printLine(cell_name + "->Leakage->DCK!Q=" + (String) leakage_110); + Log::printLine(cell_name + "->Leakage->DCKQ=" + (String) leakage_111); + // -------------------------------------------------------------------- + + /* + // Cache event energy results + double event_ck_flip = 0.0; + event_ck_flip += getGenProperties()->get("INV5_A_Flip").toDouble() + getGenProperties()->get("INV5_ZN_Flip").toDouble(); + event_ck_flip += getGenProperties()->get("INV6_A_Flip").toDouble() + getGenProperties()->get("INV6_ZN_Flip").toDouble(); + event_ck_flip += getGenProperties()->get("INVZ1_OE_Flip").toDouble() + getGenProperties()->get("INVZ1_OEN_Flip").toDouble(); + event_ck_flip += getGenProperties()->get("INVZ2_OE_Flip").toDouble() + getGenProperties()->get("INVZ2_OEN_Flip").toDouble(); + event_ck_flip += getGenProperties()->get("INVZ3_OE_Flip").toDouble() + getGenProperties()->get("INVZ3_OEN_Flip").toDouble(); + event_ck_flip += getGenProperties()->get("INVZ4_OE_Flip").toDouble() + getGenProperties()->get("INVZ4_OEN_Flip").toDouble(); + cache->set(cell_name + "->Event_CK_Flip", event_ck_flip); + Log::printLine(cell_name + "->Event_CK_Flip=" + (String) event_ck_flip); + + // Update D flip results + double event_d_flip = 0.0; + event_d_flip += getGenProperties()->get("INV1_A_Flip").toDouble() + getGenProperties()->get("INV1_ZN_Flip").toDouble(); + event_d_flip += getGenProperties()->get("INVZ1_A_Flip").toDouble(); + cache->set(cell_name + "->Event_D_Flip", event_d_flip); + Log::printLine(cell_name + "->Event_D_Flip=" + (String) event_d_flip); + // Update M flip results + double event_m_flip = 0.0; + event_m_flip += getGenProperties()->get("INVZ1_ZN_Flip").toDouble(); + event_m_flip += getGenProperties()->get("INV2_A_Flip").toDouble() + getGenProperties()->get("INV2_ZN_Flip").toDouble(); + event_m_flip += getGenProperties()->get("INVZ2_A_Flip").toDouble() + getGenProperties()->get("INVZ2_ZN_Flip").toDouble(); + event_m_flip += getGenProperties()->get("INVZ3_A_Flip").toDouble(); + cache->set(cell_name + "->Event_M_Flip", event_m_flip); + Log::printLine(cell_name + "->Event_M_Flip=" + (String) event_m_flip); + // Update Q flip results + double event_q_flip = 0.0; + event_q_flip += getGenProperties()->get("INVZ3_ZN_Flip").toDouble(); + event_q_flip += getGenProperties()->get("INV3_A_Flip").toDouble() + getGenProperties()->get("INV3_ZN_Flip").toDouble(); + event_q_flip += getGenProperties()->get("INVZ4_A_Flip").toDouble() + getGenProperties()->get("INVZ4_ZN_Flip").toDouble(); + event_q_flip += getGenProperties()->get("INV4_A_Flip").toDouble() + getGenProperties()->get("INV4_ZN_Flip").toDouble(); + cache->set(cell_name + "->Event_Q_Flip", event_q_flip); + Log::printLine(cell_name + "->Event_Q_Flip=" + (String) event_q_flip); + */ + + // -------------------------------------------------------------------- + // Get Node Capacitances + // -------------------------------------------------------------------- + double d_cap = getNet("D")->getTotalDownstreamCap(); + double d_b_cap = getNet("D_b")->getTotalDownstreamCap(); + double m_b_cap = getNet("M_b")->getTotalDownstreamCap(); + double m_cap = getNet("M")->getTotalDownstreamCap(); + double m_i_cap = getNet("M_i")->getTotalDownstreamCap(); + double q_b_cap = getNet("Q_b")->getTotalDownstreamCap(); + double q_cap = getNet("Q")->getTotalDownstreamCap(); + double ck_cap = getNet("CK")->getTotalDownstreamCap(); + double ck_b_cap = getNet("CK_b")->getTotalDownstreamCap(); + double ck_i_cap = getNet("CK_i")->getTotalDownstreamCap(); + + cache->set(cell_name + "->Cap->D", d_cap); + cache->set(cell_name + "->Cap->D_b", d_b_cap); + cache->set(cell_name + "->Cap->M_b", m_b_cap); + cache->set(cell_name + "->Cap->M", m_cap); + cache->set(cell_name + "->Cap->M_i", m_i_cap); + cache->set(cell_name + "->Cap->Q_b", q_b_cap); + cache->set(cell_name + "->Cap->Q", q_cap); + cache->set(cell_name + "->Cap->CK", ck_cap); + cache->set(cell_name + "->Cap->CK_b", ck_b_cap); + cache->set(cell_name + "->Cap->CK_i", ck_i_cap); + + Log::printLine(cell_name + "->Cap->D=" + (String) d_cap); + Log::printLine(cell_name + "->Cap->D_b=" + (String) d_b_cap); + Log::printLine(cell_name + "->Cap->M_b=" + (String) m_b_cap); + Log::printLine(cell_name + "->Cap->M=" + (String) m_cap); + Log::printLine(cell_name + "->Cap->M_i=" + (String) m_i_cap); + Log::printLine(cell_name + "->Cap->Q_b=" + (String) q_b_cap); + Log::printLine(cell_name + "->Cap->Q=" + (String) q_cap); + Log::printLine(cell_name + "->Cap->CK=" + (String) ck_cap); + Log::printLine(cell_name + "->Cap->CK_b=" + (String) ck_b_cap); + Log::printLine(cell_name + "->Cap->CK_i=" + (String) ck_i_cap); + // -------------------------------------------------------------------- + + // -------------------------------------------------------------------- + // Build Internal Delay Model + // -------------------------------------------------------------------- + double q_ron = getDriver("INV4_RonZN")->getOutputRes(); + + double d_setup_delay = getDriver("INV1_RonZN")->calculateDelay() + + getDriver("INVZ1_RonZN")->calculateDelay() + + getDriver("INV2_RonZN")->calculateDelay(); + double ck_to_q_delay = getDriver("INV5_RonZN")->calculateDelay() + + getDriver("INV6_RonZN")->calculateDelay() + + getDriver("INVZ3_RonZN")->calculateDelay() + + getDriver("INV3_RonZN")->calculateDelay() + + getDriver("INV4_RonZN")->calculateDelay(); + + cache->set(cell_name + "->DriveRes->Q", q_ron); + cache->set(cell_name + "->Delay->D_Setup", d_setup_delay); + cache->set(cell_name + "->Delay->CK_to_Q", ck_to_q_delay); + Log::printLine(cell_name + "->DriveRes->Q=" + (String) q_ron); + Log::printLine(cell_name + "->Delay->D_Setup=" + (String) d_setup_delay); + Log::printLine(cell_name + "->Delay->CK_to_Q=" + (String) ck_to_q_delay); + + return; + // -------------------------------------------------------------------- + } + +} // namespace DSENT + diff --git a/ext/dsent/model/std_cells/DFFQ.h b/ext/dsent/model/std_cells/DFFQ.h new file mode 100644 index 000000000..699e48627 --- /dev/null +++ b/ext/dsent/model/std_cells/DFFQ.h @@ -0,0 +1,38 @@ +#ifndef __DSENT_MODEL_STD_CELLS_DFFQ_H__ +#define __DSENT_MODEL_STD_CELLS_DFFQ_H__ + +#include "util/CommonType.h" +#include "model/std_cells/StdCell.h" +#include "model/TransitionInfo.h" + +namespace DSENT +{ + class DFFQ : public StdCell + { + // A DQ flip-flop + public: + DFFQ(const String& instance_name_, const TechModel* tech_model_); + virtual ~DFFQ(); + + public: + // Set a list of properties' name needed to construct model + void initProperties(); + // Cache the standard cell + void cacheStdCell(StdCellLib* cell_lib_, double drive_strength_); + + private: + TransitionInfo m_trans_M_; + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void evaluateModel(); + virtual void useModel(); + virtual void propagateTransitionInfo(); + + }; // class DFFQ +} // namespace DSENT + +#endif // __DSENT_MODEL_STD_CELLS_INV_H__ + diff --git a/ext/dsent/model/std_cells/INV.cc b/ext/dsent/model/std_cells/INV.cc new file mode 100644 index 000000000..a6ea6c4f4 --- /dev/null +++ b/ext/dsent/model/std_cells/INV.cc @@ -0,0 +1,219 @@ +#include "model/std_cells/INV.h" + +#include <cmath> + +#include "model/PortInfo.h" +#include "model/TransitionInfo.h" +#include "model/EventInfo.h" +#include "model/std_cells/CellMacros.h" +#include "model/std_cells/StdCellLib.h" +#include "model/timing_graph/ElectricalNet.h" +#include "model/timing_graph/ElectricalDriver.h" +#include "model/timing_graph/ElectricalLoad.h" +#include "model/timing_graph/ElectricalDelay.h" + +namespace DSENT +{ + using std::ceil; + using std::max; + + INV::INV(const String& instance_name_, const TechModel* tech_model_) + : StdCell(instance_name_, tech_model_) + { + initProperties(); + } + + INV::~INV() + {} + + void INV::initProperties() + { + return; + } + + void INV::constructModel() + { + // All constructModel should do is create Area/NDDPower/Energy Results as + // well as instantiate any sub-instances using only the hard parameters + + // Build Electrical Connectivity + createInputPort("A"); + createOutputPort("Y"); + + createLoad("A_Cap"); + createDelay("A_to_Y_delay"); + createDriver("Y_Ron", true); + + ElectricalLoad* a_cap = getLoad("A_Cap"); + ElectricalDelay* a_to_y_delay = getDelay("A_to_Y_delay"); + ElectricalDriver* y_ron = getDriver("Y_Ron"); + + getNet("A")->addDownstreamNode(a_cap); + a_cap->addDownstreamNode(a_to_y_delay); + a_to_y_delay->addDownstreamNode(y_ron); + y_ron->addDownstreamNode(getNet("Y")); + + // Create Area result + // Create NDD Power result + createElectricalAtomicResults(); + // Create INV Event Energy Result + createElectricalEventAtomicResult("INV"); + + getEventInfo("Idle")->setStaticTransitionInfos(); + + return; + } + + void INV::updateModel() + { + // All updateModel should do is calculate numbers for the Area/NDDPower/Energy + // Results as anything else that needs to be done using either soft or hard parameters + + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Standard cell cache string + String cell_name = "INV_X" + (String) drive_strength; + + // Get timing parameters + getLoad("A_Cap")->setLoadCap(cache->get(cell_name + "->Cap->A")); + getDriver("Y_Ron")->setOutputRes(cache->get(cell_name + "->DriveRes->Y")); + getDelay("A_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->A_to_Y")); + + // Set the cell area + getAreaResult("Active")->setValue(cache->get(cell_name + "->Area->Active")); + getAreaResult("Metal1Wire")->setValue(cache->get(cell_name + "->Area->Metal1Wire")); + + return; + } + + void INV::evaluateModel() + { + return; + } + + void INV::useModel() + { + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Standard cell cache string + String cell_name = "INV_X" + (String) drive_strength; + + // Propagate the transition info and get the 0->1 transtion count + propagateTransitionInfo(); + double P_A = getInputPort("A")->getTransitionInfo().getProbability1(); + double Y_num_trans_01 = getOutputPort("Y")->getTransitionInfo().getNumberTransitions01(); + + // Calculate leakage + double leakage = 0; + leakage += cache->get(cell_name + "->Leakage->!A") * (1 - P_A); + leakage += cache->get(cell_name + "->Leakage->A") * P_A; + getNddPowerResult("Leakage")->setValue(leakage); + + // Get VDD + double vdd = getTechModel()->get("Vdd"); + + // Get capacitances + //double a_cap = cache->get(cell_name + "->Cap->A"); + double y_cap = cache->get(cell_name + "->Cap->Y"); + double y_load_cap = getNet("Y")->getTotalDownstreamCap(); + + // Calculate INV Event energy + double energy_per_trans_01 = (y_cap + y_load_cap) * vdd * vdd; + getEventResult("INV")->setValue(energy_per_trans_01 * Y_num_trans_01); + return; + } + + void INV::propagateTransitionInfo() + { + // Get input transition info + const TransitionInfo& trans_A = getInputPort("A")->getTransitionInfo(); + + // Set output transition info + double Y_num_trans_00 = trans_A.getNumberTransitions11(); + double Y_num_trans_01 = trans_A.getNumberTransitions01(); + double Y_num_trans_11 = trans_A.getNumberTransitions00(); + + TransitionInfo trans_Y(Y_num_trans_00, Y_num_trans_01, Y_num_trans_11); + getOutputPort("Y")->setTransitionInfo(trans_Y); + return; + } + + // Creates the standard cell, characterizes and abstracts away the details + void INV::cacheStdCell(StdCellLib* cell_lib_, double drive_strength_) + { + // Standard cell cache string + String cell_name = "INV_X" + (String) drive_strength_; + + Log::printLine("=== " + cell_name + " ==="); + + // Get parameters + double gate_pitch = cell_lib_->getTechModel()->get("Gate->PitchContacted"); + Map<double>* cache = cell_lib_->getStdCellCache(); + + // Now actually build the full standard cell model + // Create the two input ports + createInputPort("A"); + createOutputPort("Y"); + + // Adds macros + CellMacros::addInverter(this, "INV", true, true, "A", "Y"); + CellMacros::updateInverter(this, "INV", drive_strength_); + + // Cache area result + double area = gate_pitch * getTotalHeight() * (1 + getGenProperties()->get("INV_GatePitches").toDouble()); + cache->set(cell_name + "->Area->Active", area); + cache->set(cell_name + "->Area->Metal1Wire", area); + Log::printLine(cell_name + "->Area->Active=" + (String) area); + Log::printLine(cell_name + "->Area->Metal1Wire=" + (String) area); + + // -------------------------------------------------------------------- + // Leakage Model Calculation + // -------------------------------------------------------------------- + double leakage_a0 = getGenProperties()->get("INV_LeakagePower_0").toDouble(); + double leakage_a1 = getGenProperties()->get("INV_LeakagePower_1").toDouble(); + cache->set(cell_name + "->Leakage->!A", leakage_a0); + cache->set(cell_name + "->Leakage->A", leakage_a1); + Log::printLine(cell_name + "->Leakage->!A=" + (String) leakage_a0); + Log::printLine(cell_name + "->Leakage->A=" + (String) leakage_a1); + // -------------------------------------------------------------------- + + /* + // Cache event energy results + double event_a_flip = getGenProperties()->get("INV_A_Flip").toDouble() + getGenProperties()->get("INV_ZN_Flip").toDouble(); + cache->set(cell_name + "->Event_A_Flip", event_a_flip); + Log::printLine(cell_name + "->Event_A_Flip=" + (String) event_a_flip); + */ + + // -------------------------------------------------------------------- + // Get Node Capacitances + // -------------------------------------------------------------------- + double a_cap = getNet("A")->getTotalDownstreamCap(); + double y_cap = getNet("Y")->getTotalDownstreamCap(); + + cache->set(cell_name + "->Cap->A", a_cap); + cache->set(cell_name + "->Cap->Y", y_cap); + Log::printLine(cell_name + "->Cap->A=" + (String) a_cap); + Log::printLine(cell_name + "->Cap->Y=" + (String) y_cap); + // -------------------------------------------------------------------- + + // -------------------------------------------------------------------- + // Build Internal Delay Model + // -------------------------------------------------------------------- + double y_ron = getDriver("INV_RonZN")->getOutputRes(); + double a_to_y_delay = getDriver("INV_RonZN")->calculateDelay(); + cache->set(cell_name + "->DriveRes->Y", y_ron); + cache->set(cell_name + "->Delay->A_to_Y", a_to_y_delay); + Log::printLine(cell_name + "->DriveRes->Y=" + (String) y_ron); + Log::printLine(cell_name + "->Delay->A_to_Y=" + (String) a_to_y_delay); + // -------------------------------------------------------------------- + + return; + + } + +} // namespace DSENT + diff --git a/ext/dsent/model/std_cells/INV.h b/ext/dsent/model/std_cells/INV.h new file mode 100644 index 000000000..d81d207c6 --- /dev/null +++ b/ext/dsent/model/std_cells/INV.h @@ -0,0 +1,34 @@ +#ifndef __DSENT_MODEL_STD_CELLS_INV_H__ +#define __DSENT_MODEL_STD_CELLS_INV_H__ + +#include "util/CommonType.h" +#include "model/std_cells/StdCell.h" + +namespace DSENT +{ + class INV : public StdCell + { + public: + INV(const String& instance_name_, const TechModel* tech_model_); + virtual ~INV(); + + public: + // Set a list of properties' name needed to construct model + void initProperties(); + + // Cache the standard cell + void cacheStdCell(StdCellLib* cell_lib_, double drive_strength_); + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void evaluateModel(); + virtual void useModel(); + virtual void propagateTransitionInfo(); + + }; // class INV +} // namespace DSENT + +#endif // __DSENT_MODEL_STD_CELLS_INV_H__ + diff --git a/ext/dsent/model/std_cells/LATQ.cc b/ext/dsent/model/std_cells/LATQ.cc new file mode 100644 index 000000000..b2548d07b --- /dev/null +++ b/ext/dsent/model/std_cells/LATQ.cc @@ -0,0 +1,380 @@ +#include "model/std_cells/LATQ.h" + +#include <cmath> + +#include "model/PortInfo.h" +#include "model/TransitionInfo.h" +#include "model/EventInfo.h" +#include "model/std_cells/StdCellLib.h" +#include "model/std_cells/CellMacros.h" +#include "model/timing_graph/ElectricalNet.h" +#include "model/timing_graph/ElectricalDriver.h" +#include "model/timing_graph/ElectricalLoad.h" +#include "model/timing_graph/ElectricalDelay.h" + +namespace DSENT +{ + using std::ceil; + using std::max; + using std::min; + + LATQ::LATQ(const String& instance_name_, const TechModel* tech_model_) + : StdCell(instance_name_, tech_model_) + { + initProperties(); + } + + LATQ::~LATQ() + {} + + void LATQ::initProperties() + { + return; + } + + void LATQ::constructModel() + { + // All constructModel should do is create Area/NDDPower/Energy Results as + // well as instantiate any sub-instances using only the hard parameters + + createInputPort("D"); + createInputPort("G"); + createOutputPort("Q"); + + createLoad("D_Cap"); + createLoad("G_Cap"); + createDelay("D_to_Q_delay"); + createDelay("G_to_Q_delay"); + createDriver("Q_Ron", true); + + ElectricalLoad* d_cap = getLoad("D_Cap"); + ElectricalLoad* g_cap = getLoad("G_Cap"); + ElectricalDelay* d_to_q_delay = getDelay("D_to_Q_delay"); + ElectricalDelay* g_to_q_delay = getDelay("G_to_Q_delay"); + ElectricalDriver* q_ron = getDriver("Q_Ron"); + + getNet("D")->addDownstreamNode(d_cap); + getNet("G")->addDownstreamNode(g_cap); + d_cap->addDownstreamNode(d_to_q_delay); + g_cap->addDownstreamNode(g_to_q_delay); + g_to_q_delay->addDownstreamNode(q_ron); + q_ron->addDownstreamNode(getNet("Q")); + + // Create Area result + // Create NDD Power result + createElectricalAtomicResults(); + // Create G Event Energy Result + createElectricalEventAtomicResult("G"); + // Create DFF Event Energy Result + createElectricalEventAtomicResult("LATD"); + createElectricalEventAtomicResult("LATQ"); + // Create Idle event for leakage + // G pin is assumed to be on all the time + //createElectricalEventAtomicResult("Idle"); + getEventInfo("Idle")->setStaticTransitionInfos(); + return; + } + + void LATQ::updateModel() + { + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Standard cell cache string + String cell_name = "LATQ_X" + (String) drive_strength; + + // Get timing parameters + getLoad("D_Cap")->setLoadCap(cache->get(cell_name + "->Cap->D")); + getLoad("G_Cap")->setLoadCap(cache->get(cell_name + "->Cap->G")); + getDriver("Q_Ron")->setOutputRes(cache->get(cell_name + "->DriveRes->Q")); + getDelay("G_to_Q_delay")->setDelay(cache->get(cell_name + "->Delay->G_to_Q")); + getDelay("D_to_Q_delay")->setDelay(cache->get(cell_name + "->Delay->D_to_Q")); + + // Set the cell area + getAreaResult("Active")->setValue(cache->get(cell_name + "->Area->Active")); + getAreaResult("Metal1Wire")->setValue(cache->get(cell_name + "->Area->Metal1Wire")); + + return; + } + + void LATQ::evaluateModel() + { + return; + } + + void LATQ::useModel() + { + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Standard cell cache string + String cell_name = "LATQ_X" + (String) drive_strength; + + // Propagate the transition info and get P_D, P_M, and P_Q + propagateTransitionInfo(); + double P_D = getInputPort("D")->getTransitionInfo().getProbability1(); + double P_G = getInputPort("G")->getTransitionInfo().getProbability1(); + double P_Q = getOutputPort("Q")->getTransitionInfo().getProbability1(); + double G_num_trans_01 = getInputPort("G")->getTransitionInfo().getNumberTransitions01(); + double D_num_trans_01 = getInputPort("D")->getTransitionInfo().getNumberTransitions01(); + double Q_num_trans_01 = getOutputPort("Q")->getTransitionInfo().getNumberTransitions01(); + + // Calculate leakage + double leakage = 0; + leakage += cache->get(cell_name + "->Leakage->!D!G!Q") * (1 - P_D) * (1 - P_G) * (1 - P_Q); + leakage += cache->get(cell_name + "->Leakage->!D!GQ") * (1 - P_D) * (1 - P_G) * P_Q; + leakage += cache->get(cell_name + "->Leakage->!DG!Q") * (1 - P_D) * P_G * (1 - P_Q); + leakage += cache->get(cell_name + "->Leakage->D!G!Q") * P_D * (1 - P_G) * (1 - P_Q); + leakage += cache->get(cell_name + "->Leakage->D!GQ") * P_D * (1 - P_G) * P_Q; + leakage += cache->get(cell_name + "->Leakage->DGQ") * P_D * P_G * P_Q; + getNddPowerResult("Leakage")->setValue(leakage); + + // Get VDD + double vdd = getTechModel()->get("Vdd"); + + // Get capacitances + double g_b_cap = cache->get(cell_name + "->Cap->G_b"); + double d_b_cap = cache->get(cell_name + "->Cap->D_b"); + double q_i_cap = cache->get(cell_name + "->Cap->Q_i"); + double q_b_cap = cache->get(cell_name + "->Cap->Q_b"); + double q_cap = cache->get(cell_name + "->Cap->Q"); + double q_load_cap = getNet("Q")->getTotalDownstreamCap(); + + // Calculate G Event energy + double g_event_energy = 0.0; + g_event_energy += (g_b_cap) * G_num_trans_01; + g_event_energy *= vdd * vdd; + getEventResult("G")->setValue(g_event_energy); + // Calculate LATD Event energy + double latd_event_energy = 0.0; + latd_event_energy += (d_b_cap) * D_num_trans_01; + latd_event_energy *= vdd * vdd; + getEventResult("LATD")->setValue(latd_event_energy); + // Calculate LATQ Event energy + double latq_event_energy = 0.0; + latq_event_energy += (q_i_cap + q_b_cap + q_cap + q_load_cap) * Q_num_trans_01; + latq_event_energy *= vdd * vdd; + getEventResult("LATQ")->setValue(latq_event_energy); + + return; + } + + void LATQ::propagateTransitionInfo() + { + const TransitionInfo& trans_G = getInputPort("G")->getTransitionInfo(); + const TransitionInfo& trans_D = getInputPort("D")->getTransitionInfo(); + + double G_num_trans_01 = trans_G.getNumberTransitions01(); + double G_num_trans_10 = G_num_trans_01; + double G_num_trans_00 = trans_G.getNumberTransitions00(); + double D_freq_mult = trans_D.getFrequencyMultiplier(); + + // If the latch is sampling just as fast or faster than input data signal + // Then it can capture all transitions (though it should be normalized to clock) + if((G_num_trans_10 + G_num_trans_00) >= D_freq_mult) + { + const TransitionInfo& trans_Q = trans_D.scaleFrequencyMultiplier(G_num_trans_10 + G_num_trans_00); + getOutputPort("Q")->setTransitionInfo(trans_Q); + } + // If the latch is sampling slower than the input data signal, then input + // will look like they transition more + else + { + // Calculate scale ratio + double scale_ratio = (G_num_trans_10 + G_num_trans_00) / D_freq_mult; + // 00 and 11 transitions become fewer + double D_scaled_diff = 0.5 * (1 - scale_ratio) * (trans_D.getNumberTransitions00() + trans_D.getNumberTransitions11()); + double D_scaled_num_trans_00 = trans_D.getNumberTransitions00() * scale_ratio; + double D_scaled_num_trans_11 = trans_D.getNumberTransitions11() * scale_ratio; + // 01 and 10 transitions become more frequent + double D_scaled_num_trans_10 = trans_D.getNumberTransitions01() + D_scaled_diff; + + // Create final transition info, remembering to apply scaling ratio to normalize to G + const TransitionInfo trans_Q( D_scaled_num_trans_00 * scale_ratio, + D_scaled_num_trans_10 * scale_ratio, + D_scaled_num_trans_11 * scale_ratio); + getOutputPort("Q")->setTransitionInfo(trans_Q); + } + + return; + } + + // Creates the standard cell, characterizes and abstracts away the details + void LATQ::cacheStdCell(StdCellLib* cell_lib_, double drive_strength_) + { + // Get parameters + double gate_pitch = cell_lib_->getTechModel()->get("Gate->PitchContacted"); + Map<double>* cache = cell_lib_->getStdCellCache(); + + // Standard cell cache string + String cell_name = "LATQ_X" + (String) drive_strength_; + + Log::printLine("=== " + cell_name + " ==="); + + + // Now actually build the full standard cell model + createInputPort("D"); + createInputPort("G"); + createOutputPort("Q"); + + createNet("D_b"); + createNet("Q_i"); + createNet("Q_b"); + createNet("G_b"); + + // Adds macros + CellMacros::addInverter(this, "INV1", false, true, "D", "D_b"); + CellMacros::addInverter(this, "INV2", false, true, "Q_i", "Q_b"); + CellMacros::addInverter(this, "INV3", false, true, "Q_b", "Q"); + CellMacros::addInverter(this, "INV4", false, true, "G", "G_b"); + CellMacros::addTristate(this, "INVZ1", false, true, false, false, "D_b", "G", "G_b", "Q_i"); //trace timing through A->ZN path only + CellMacros::addTristate(this, "INVZ2", false, false, false, false, "Q_b", "G_b", "G", "Q_i"); //don't trace timing through the feedback path + + // Update macros + CellMacros::updateInverter(this, "INV1", drive_strength_ * 0.125); + CellMacros::updateInverter(this, "INV2", drive_strength_ * 0.5); + CellMacros::updateInverter(this, "INV3", drive_strength_ * 1.0); + CellMacros::updateInverter(this, "INV4", drive_strength_ * 0.125); + CellMacros::updateTristate(this, "INVZ1", drive_strength_ * 0.5); + CellMacros::updateTristate(this, "INVZ2", drive_strength_ * 0.0625); + + // Cache area result + double area = 0.0; + area += gate_pitch * getTotalHeight() * 1; + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV1_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV2_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV3_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV4_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ1_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ2_GatePitches").toDouble(); + cache->set(cell_name + "->Area->Active", area); + cache->set(cell_name + "->Area->Metal1Wire", area); //Cover-block m1 area + Log::printLine(cell_name + "->Area->Active=" + (String) area); + Log::printLine(cell_name + "->Area->Metal1Wire=" + (String) area); + + // -------------------------------------------------------------------- + // Leakage Model Calculation + // -------------------------------------------------------------------- + // Cache leakage power results (for every single signal combination) + double leakage_000 = 0; //!D, !G, !Q + double leakage_001 = 0; //!D, !G, Q + double leakage_010 = 0; //!D, G, !Q + double leakage_100 = 0; //D, !G, !Q + double leakage_101 = 0; //D, !G, Q + double leakage_111 = 0; //D, G, Q + + //This is so painful... + leakage_000 += getGenProperties()->get("INV1_LeakagePower_0").toDouble(); + leakage_000 += getGenProperties()->get("INV2_LeakagePower_0").toDouble(); + leakage_000 += getGenProperties()->get("INV3_LeakagePower_1").toDouble(); + leakage_000 += getGenProperties()->get("INV4_LeakagePower_0").toDouble(); + leakage_000 += getGenProperties()->get("INVZ1_LeakagePower_011_0").toDouble(); + leakage_000 += getGenProperties()->get("INVZ2_LeakagePower_101_0").toDouble(); + + leakage_001 += getGenProperties()->get("INV1_LeakagePower_0").toDouble(); + leakage_001 += getGenProperties()->get("INV2_LeakagePower_0").toDouble(); + leakage_001 += getGenProperties()->get("INV3_LeakagePower_0").toDouble(); + leakage_001 += getGenProperties()->get("INV4_LeakagePower_0").toDouble(); + leakage_001 += getGenProperties()->get("INVZ1_LeakagePower_011_1").toDouble(); + leakage_001 += getGenProperties()->get("INVZ2_LeakagePower_100_1").toDouble(); + + leakage_010 += getGenProperties()->get("INV1_LeakagePower_0").toDouble(); + leakage_010 += getGenProperties()->get("INV2_LeakagePower_0").toDouble(); + leakage_010 += getGenProperties()->get("INV3_LeakagePower_1").toDouble(); + leakage_010 += getGenProperties()->get("INV4_LeakagePower_1").toDouble(); + leakage_010 += getGenProperties()->get("INVZ1_LeakagePower_101_0").toDouble(); + leakage_010 += getGenProperties()->get("INVZ2_LeakagePower_011_0").toDouble(); + + leakage_100 += getGenProperties()->get("INV1_LeakagePower_1").toDouble(); + leakage_100 += getGenProperties()->get("INV2_LeakagePower_1").toDouble(); + leakage_100 += getGenProperties()->get("INV3_LeakagePower_1").toDouble(); + leakage_100 += getGenProperties()->get("INV4_LeakagePower_0").toDouble(); + leakage_100 += getGenProperties()->get("INVZ1_LeakagePower_010_0").toDouble(); + leakage_100 += getGenProperties()->get("INVZ2_LeakagePower_101_0").toDouble(); + + leakage_101 += getGenProperties()->get("INV1_LeakagePower_1").toDouble(); + leakage_101 += getGenProperties()->get("INV2_LeakagePower_1").toDouble(); + leakage_101 += getGenProperties()->get("INV3_LeakagePower_0").toDouble(); + leakage_101 += getGenProperties()->get("INV4_LeakagePower_0").toDouble(); + leakage_101 += getGenProperties()->get("INVZ1_LeakagePower_010_1").toDouble(); + leakage_101 += getGenProperties()->get("INVZ2_LeakagePower_100_1").toDouble(); + + leakage_111 += getGenProperties()->get("INV1_LeakagePower_1").toDouble(); + leakage_111 += getGenProperties()->get("INV2_LeakagePower_1").toDouble(); + leakage_111 += getGenProperties()->get("INV3_LeakagePower_0").toDouble(); + leakage_111 += getGenProperties()->get("INV4_LeakagePower_1").toDouble(); + leakage_111 += getGenProperties()->get("INVZ1_LeakagePower_100_1").toDouble(); + leakage_111 += getGenProperties()->get("INVZ2_LeakagePower_010_1").toDouble(); + + cache->set(cell_name + "->Leakage->!D!G!Q", leakage_000); + cache->set(cell_name + "->Leakage->!D!GQ", leakage_001); + cache->set(cell_name + "->Leakage->!DG!Q", leakage_010); + cache->set(cell_name + "->Leakage->D!G!Q", leakage_100); + cache->set(cell_name + "->Leakage->D!GQ", leakage_101); + cache->set(cell_name + "->Leakage->DGQ", leakage_111); + Log::printLine(cell_name + "->Leakage->!D!G!Q=" + (String) leakage_000); + Log::printLine(cell_name + "->Leakage->!D!GQ=" + (String) leakage_001); + Log::printLine(cell_name + "->Leakage->!DG!Q=" + (String) leakage_010); + Log::printLine(cell_name + "->Leakage->D!G!Q=" + (String) leakage_100); + Log::printLine(cell_name + "->Leakage->D!GQ=" + (String) leakage_101); + Log::printLine(cell_name + "->Leakage->DGQ=" + (String) leakage_111); + // -------------------------------------------------------------------- + + // -------------------------------------------------------------------- + // Get Node Capacitances + // -------------------------------------------------------------------- + double d_cap = getNet("D")->getTotalDownstreamCap(); + double d_b_cap = getNet("D_b")->getTotalDownstreamCap(); + double q_i_cap = getNet("Q_i")->getTotalDownstreamCap(); + double q_b_cap = getNet("Q_b")->getTotalDownstreamCap(); + double q_cap = getNet("Q")->getTotalDownstreamCap(); + double g_cap = getNet("G")->getTotalDownstreamCap(); + double g_b_cap = getNet("G_b")->getTotalDownstreamCap(); + + cache->set(cell_name + "->Cap->D", d_cap); + cache->set(cell_name + "->Cap->D_b", d_b_cap); + cache->set(cell_name + "->Cap->Q_i", q_i_cap); + cache->set(cell_name + "->Cap->Q_b", q_b_cap); + cache->set(cell_name + "->Cap->Q", q_cap); + cache->set(cell_name + "->Cap->G", g_cap); + cache->set(cell_name + "->Cap->G_b", g_b_cap); + + Log::printLine(cell_name + "->Cap->D=" + (String) d_cap); + Log::printLine(cell_name + "->Cap->D_b=" + (String) d_b_cap); + Log::printLine(cell_name + "->Cap->Q_i=" + (String) q_i_cap); + Log::printLine(cell_name + "->Cap->Q_b=" + (String) q_b_cap); + Log::printLine(cell_name + "->Cap->Q=" + (String) q_cap); + Log::printLine(cell_name + "->Cap->G=" + (String) g_cap); + Log::printLine(cell_name + "->Cap->G_b=" + (String) g_b_cap); + // -------------------------------------------------------------------- + + // -------------------------------------------------------------------- + // Build Internal Delay Model + // -------------------------------------------------------------------- + double q_ron = getDriver("INV3_RonZN")->getOutputRes(); + + double d_to_q_delay = getDriver("INV1_RonZN")->calculateDelay() + + getDriver("INVZ1_RonZN")->calculateDelay() + + getDriver("INV2_RonZN")->calculateDelay() + + getDriver("INV3_RonZN")->calculateDelay(); + double g_to_q_delay = getDriver("INV4_RonZN")->calculateDelay() + + getDriver("INVZ1_RonZN")->calculateDelay() + + getDriver("INV2_RonZN")->calculateDelay() + + getDriver("INV3_RonZN")->calculateDelay(); + + cache->set(cell_name + "->DriveRes->Q", q_ron); + cache->set(cell_name + "->Delay->D_to_Q", d_to_q_delay); + cache->set(cell_name + "->Delay->G_to_Q", g_to_q_delay); + Log::printLine(cell_name + "->DriveRes->Q=" + (String) q_ron); + Log::printLine(cell_name + "->Delay->D_to_Q=" + (String) d_to_q_delay); + Log::printLine(cell_name + "->Delay->G_to_Q=" + (String) g_to_q_delay); + + return; + // -------------------------------------------------------------------- + + } + +} // namespace DSENT + diff --git a/ext/dsent/model/std_cells/LATQ.h b/ext/dsent/model/std_cells/LATQ.h new file mode 100644 index 000000000..7dcb26fd5 --- /dev/null +++ b/ext/dsent/model/std_cells/LATQ.h @@ -0,0 +1,34 @@ +#ifndef __DSENT_MODEL_STD_CELLS_LATQ_H__ +#define __DSENT_MODEL_STD_CELLS_LATQ_H__ + +#include "util/CommonType.h" +#include "model/std_cells/StdCell.h" + +namespace DSENT +{ + class LATQ : public StdCell + { + // A DQ flip-flop + public: + LATQ(const String& instance_name_, const TechModel* tech_model_); + virtual ~LATQ(); + + public: + // Set a list of properties' name needed to construct model + void initProperties(); + // Cache the standard cell + void cacheStdCell(StdCellLib* cell_lib_, double drive_strength_); + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void evaluateModel(); + virtual void useModel(); + virtual void propagateTransitionInfo(); + + }; // class LATQ +} // namespace DSENT + +#endif // __DSENT_MODEL_STD_CELLS_LATQ_H__ + diff --git a/ext/dsent/model/std_cells/MUX2.cc b/ext/dsent/model/std_cells/MUX2.cc new file mode 100644 index 000000000..73f18f7b6 --- /dev/null +++ b/ext/dsent/model/std_cells/MUX2.cc @@ -0,0 +1,420 @@ +#include "model/std_cells/MUX2.h" + +#include <cmath> + +#include "model/PortInfo.h" +#include "model/TransitionInfo.h" +#include "model/EventInfo.h" +#include "model/std_cells/StdCellLib.h" +#include "model/std_cells/CellMacros.h" +#include "model/timing_graph/ElectricalNet.h" +#include "model/timing_graph/ElectricalDriver.h" +#include "model/timing_graph/ElectricalLoad.h" +#include "model/timing_graph/ElectricalDelay.h" + +namespace DSENT +{ + using std::ceil; + using std::max; + + MUX2::MUX2(const String& instance_name_, const TechModel* tech_model_) + : StdCell(instance_name_, tech_model_) + { + initProperties(); + } + + MUX2::~MUX2() + {} + + void MUX2::initProperties() + { + return; + } + + void MUX2::constructModel() + { + // All constructModel should do is create Area/NDDPower/Energy Results as + // well as instantiate any sub-instances using only the hard parameters + + createInputPort("A"); + createInputPort("B"); + createInputPort("S0"); + createOutputPort("Y"); + + createLoad("A_Cap"); + createLoad("B_Cap"); + createLoad("S0_Cap"); + createDelay("A_to_Y_delay"); + createDelay("B_to_Y_delay"); + createDelay("S0_to_Y_delay"); + createDriver("Y_Ron", true); + + ElectricalLoad* a_cap = getLoad("A_Cap"); + ElectricalLoad* b_cap = getLoad("B_Cap"); + ElectricalLoad* s0_cap = getLoad("S0_Cap"); + ElectricalDelay* a_to_y_delay = getDelay("A_to_Y_delay"); + ElectricalDelay* b_to_y_delay = getDelay("B_to_Y_delay"); + ElectricalDelay* s0_to_y_delay = getDelay("S0_to_Y_delay"); + ElectricalDriver* y_ron = getDriver("Y_Ron"); + + getNet("A")->addDownstreamNode(a_cap); + getNet("B")->addDownstreamNode(b_cap); + getNet("S0")->addDownstreamNode(s0_cap); + a_cap->addDownstreamNode(a_to_y_delay); + b_cap->addDownstreamNode(b_to_y_delay); + s0_cap->addDownstreamNode(s0_to_y_delay); + a_to_y_delay->addDownstreamNode(y_ron); + b_to_y_delay->addDownstreamNode(y_ron); + s0_to_y_delay->addDownstreamNode(y_ron); + y_ron->addDownstreamNode(getNet("Y")); + + // Create Area result + createElectricalAtomicResults(); + getEventInfo("Idle")->setStaticTransitionInfos(); + // Create MUX2 Event Energy Result + createElectricalEventAtomicResult("MUX2"); + + + return; + } + + void MUX2::updateModel() + { + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Standard cell cache string + String cell_name = "MUX2_X" + (String) drive_strength; + + // Get timing parameters + getLoad("A_Cap")->setLoadCap(cache->get(cell_name + "->Cap->A")); + getLoad("B_Cap")->setLoadCap(cache->get(cell_name + "->Cap->B")); + getLoad("S0_Cap")->setLoadCap(cache->get(cell_name + "->Cap->S0")); + + getDelay("A_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->A_to_Y")); + getDelay("B_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->B_to_Y")); + getDelay("S0_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->S0_to_Y")); + + getDriver("Y_Ron")->setOutputRes(cache->get(cell_name + "->DriveRes->Y")); + + // Set the cell area + getAreaResult("Active")->setValue(cache->get(cell_name + "->ActiveArea")); + getAreaResult("Metal1Wire")->setValue(cache->get(cell_name + "->ActiveArea")); + + return; + } + + void MUX2::evaluateModel() + { + return; + } + + void MUX2::useModel() + { + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Standard cell cache string + String cell_name = "MUX2_X" + (String) drive_strength; + + // Propagate the transition and get the 0->1 transition count + propagateTransitionInfo(); + double P_A = getInputPort("A")->getTransitionInfo().getProbability1(); + double P_B = getInputPort("B")->getTransitionInfo().getProbability1(); + double P_S0 = getInputPort("S0")->getTransitionInfo().getProbability1(); + double S0_num_trans_01 = getInputPort("S0")->getTransitionInfo().getNumberTransitions01(); + double Y_num_trans_01 = getOutputPort("Y")->getTransitionInfo().getNumberTransitions01(); + + // Calculate leakage + double leakage = 0; + leakage += cache->get(cell_name + "->Leakage->!A!B!S0") * (1 - P_A) * (1 - P_B) * (1 - P_S0); + leakage += cache->get(cell_name + "->Leakage->!A!BS0") * (1 - P_A) * (1 - P_B) * P_S0; + leakage += cache->get(cell_name + "->Leakage->!AB!S0") * (1 - P_A) * P_B * (1 - P_S0); + leakage += cache->get(cell_name + "->Leakage->!ABS0") * (1 - P_A) * P_B * P_S0; + leakage += cache->get(cell_name + "->Leakage->A!B!S0") * P_A * (1 - P_B) * (1 - P_S0); + leakage += cache->get(cell_name + "->Leakage->A!BS0") * P_A * (1 - P_B) * P_S0; + leakage += cache->get(cell_name + "->Leakage->AB!S0") * P_A * P_B * (1 - P_S0); + leakage += cache->get(cell_name + "->Leakage->ABS0") * P_A * P_B * P_S0; + getNddPowerResult("Leakage")->setValue(leakage); + + // Get VDD + double vdd = getTechModel()->get("Vdd"); + + // Get capacitances + double s0_b_cap = cache->get(cell_name + "->Cap->S0_b"); + double y_bar_cap = cache->get(cell_name + "->Cap->Y_b"); + double y_cap = cache->get(cell_name + "->Cap->Y"); + double y_load_cap = getNet("Y")->getTotalDownstreamCap(); + // Create mux2 event energy + double mux2_event_energy = 0.0; + mux2_event_energy += (s0_b_cap) * S0_num_trans_01; + mux2_event_energy += (y_bar_cap + y_cap + y_load_cap) * Y_num_trans_01; + mux2_event_energy *= vdd * vdd; + getEventResult("MUX2")->setValue(mux2_event_energy); + + return; + } + + void MUX2::propagateTransitionInfo() + { + // Get input signal transition info + const TransitionInfo& trans_A = getInputPort("A")->getTransitionInfo(); + const TransitionInfo& trans_B = getInputPort("B")->getTransitionInfo(); + const TransitionInfo& trans_S0 = getInputPort("S0")->getTransitionInfo(); + + // Scale all transition information to the highest freq multiplier + double max_freq_mult = max(max(trans_A.getFrequencyMultiplier(), trans_B.getFrequencyMultiplier()), trans_S0.getFrequencyMultiplier()); + const TransitionInfo& scaled_trans_A = trans_A.scaleFrequencyMultiplier(max_freq_mult); + const TransitionInfo& scaled_trans_B = trans_B.scaleFrequencyMultiplier(max_freq_mult); + const TransitionInfo& scaled_trans_S0 = trans_S0.scaleFrequencyMultiplier(max_freq_mult); + + // Compute the probability of each transition on a given cycle + double A_prob_00 = scaled_trans_A.getNumberTransitions00() / max_freq_mult; + double A_prob_01 = scaled_trans_A.getNumberTransitions01() / max_freq_mult; + double A_prob_10 = A_prob_01; + double A_prob_11 = scaled_trans_A.getNumberTransitions11() / max_freq_mult; + double B_prob_00 = scaled_trans_B.getNumberTransitions00() / max_freq_mult; + double B_prob_01 = scaled_trans_B.getNumberTransitions01() / max_freq_mult; + double B_prob_10 = B_prob_01; + double B_prob_11 = scaled_trans_B.getNumberTransitions11() / max_freq_mult; + double S0_prob_00 = scaled_trans_S0.getNumberTransitions00() / max_freq_mult; + double S0_prob_01 = scaled_trans_S0.getNumberTransitions01() / max_freq_mult; + double S0_prob_10 = S0_prob_01; + double S0_prob_11 = scaled_trans_S0.getNumberTransitions11() / max_freq_mult; + + // Compute output probabilities + double Y_prob_00 = S0_prob_00 * A_prob_00 + + S0_prob_01 * (A_prob_00 + A_prob_01) * (B_prob_00 + B_prob_10) + + S0_prob_10 * (A_prob_00 + A_prob_10) * (B_prob_00 + B_prob_01) + + S0_prob_11 * B_prob_00; + double Y_prob_01 = S0_prob_00 * A_prob_01 + + S0_prob_01 * (A_prob_00 + A_prob_01) * (B_prob_01 + B_prob_11) + + S0_prob_10 * (A_prob_01 + A_prob_11) * (B_prob_00 + B_prob_01) + + S0_prob_11 * B_prob_01; + double Y_prob_11 = S0_prob_00 * A_prob_11 + + S0_prob_01 * (A_prob_10 + A_prob_11) * (B_prob_01 + B_prob_11) + + S0_prob_10 * (A_prob_01 + A_prob_11) * (B_prob_10 + B_prob_11) + + S0_prob_11 * B_prob_11; + + // Check that probabilities add up to 1.0 with some finite tolerance + ASSERT(LibUtil::Math::isEqual((Y_prob_00 + Y_prob_01 + Y_prob_01 + Y_prob_11), 1.0), + "[Error] " + getInstanceName() + "Output transition probabilities must add up to 1 (" + + (String) Y_prob_00 + ", " + (String) Y_prob_01 + ", " + (String) Y_prob_11 + ")!"); + + // Turn probability of transitions per cycle into number of transitions per time unit + TransitionInfo trans_Y(Y_prob_00 * max_freq_mult, Y_prob_01 * max_freq_mult, Y_prob_11 * max_freq_mult); + getOutputPort("Y")->setTransitionInfo(trans_Y); + + return; + } + + // Creates the standard cell, characterizes and abstracts away the details + void MUX2::cacheStdCell(StdCellLib* cell_lib_, double drive_strength_) + { + // Get parameters + double gate_pitch = cell_lib_->getTechModel()->get("Gate->PitchContacted"); + Map<double>* cache = cell_lib_->getStdCellCache(); + + // Standard cell cache string + String cell_name = "MUX2_X" + (String) drive_strength_; + + Log::printLine("=== " + cell_name + " ==="); + + // Now actually build the full standard cell model + createInputPort("A"); + createInputPort("B"); + createInputPort("S0"); + createOutputPort("Y"); + + createNet("S0_b"); + createNet("Y_b"); + + // Adds macros + CellMacros::addInverter(this, "INV1", false, true, "S0", "S0_b"); + CellMacros::addInverter(this, "INV2", false, true, "Y_b", "Y"); + CellMacros::addTristate(this, "INVZ1", true, true, true, true, "A", "S0_b", "S0", "Y_b"); + CellMacros::addTristate(this, "INVZ2", true, true, true, true, "B", "S0", "S0_b", "Y_b"); + + // I have no idea how to size each of the parts haha + CellMacros::updateInverter(this, "INV1", drive_strength_ * 0.250); + CellMacros::updateInverter(this, "INV2", drive_strength_ * 1.000); + CellMacros::updateTristate(this, "INVZ1", drive_strength_ * 0.500); + CellMacros::updateTristate(this, "INVZ2", drive_strength_ * 0.500); + + // Cache area result + double area = 0.0; + area += gate_pitch * getTotalHeight() * 1; + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV1_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV2_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ1_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ2_GatePitches").toDouble(); + cache->set(cell_name + "->ActiveArea", area); + Log::printLine(cell_name + "->ActiveArea=" + (String) area); + + // -------------------------------------------------------------------- + // Cache Leakage Power (for every single signal combination) + // -------------------------------------------------------------------- + double leakage_000 = 0; //!A, !B, !S0 + double leakage_001 = 0; //!A, !B, S0 + double leakage_010 = 0; //!A, B, !S0 + double leakage_011 = 0; //!A, B, S0 + double leakage_100 = 0; //A, !B, !S0 + double leakage_101 = 0; //A, !B, S0 + double leakage_110 = 0; //A, B, !S0 + double leakage_111 = 0; //A, B, S0 + + //This is so painful... + leakage_000 += getGenProperties()->get("INV1_LeakagePower_0").toDouble(); + leakage_000 += getGenProperties()->get("INV2_LeakagePower_1").toDouble(); + leakage_000 += getGenProperties()->get("INVZ1_LeakagePower_100_1").toDouble(); + leakage_000 += getGenProperties()->get("INVZ2_LeakagePower_010_1").toDouble(); + + leakage_001 += getGenProperties()->get("INV1_LeakagePower_1").toDouble(); + leakage_001 += getGenProperties()->get("INV2_LeakagePower_1").toDouble(); + leakage_001 += getGenProperties()->get("INVZ1_LeakagePower_010_1").toDouble(); + leakage_001 += getGenProperties()->get("INVZ2_LeakagePower_100_1").toDouble(); + + leakage_010 += getGenProperties()->get("INV1_LeakagePower_0").toDouble(); + leakage_010 += getGenProperties()->get("INV2_LeakagePower_1").toDouble(); + leakage_010 += getGenProperties()->get("INVZ1_LeakagePower_100_1").toDouble(); + leakage_010 += getGenProperties()->get("INVZ2_LeakagePower_011_1").toDouble(); + + leakage_011 += getGenProperties()->get("INV1_LeakagePower_1").toDouble(); + leakage_011 += getGenProperties()->get("INV2_LeakagePower_0").toDouble(); + leakage_011 += getGenProperties()->get("INVZ1_LeakagePower_010_0").toDouble(); + leakage_011 += getGenProperties()->get("INVZ2_LeakagePower_101_0").toDouble(); + + leakage_100 += getGenProperties()->get("INV1_LeakagePower_0").toDouble(); + leakage_100 += getGenProperties()->get("INV2_LeakagePower_0").toDouble(); + leakage_100 += getGenProperties()->get("INVZ1_LeakagePower_101_0").toDouble(); + leakage_100 += getGenProperties()->get("INVZ2_LeakagePower_010_0").toDouble(); + + leakage_101 += getGenProperties()->get("INV1_LeakagePower_1").toDouble(); + leakage_101 += getGenProperties()->get("INV2_LeakagePower_0").toDouble(); + leakage_101 += getGenProperties()->get("INVZ1_LeakagePower_011_1").toDouble(); + leakage_101 += getGenProperties()->get("INVZ2_LeakagePower_100_1").toDouble(); + + leakage_110 += getGenProperties()->get("INV1_LeakagePower_1").toDouble(); + leakage_110 += getGenProperties()->get("INV2_LeakagePower_1").toDouble(); + leakage_110 += getGenProperties()->get("INVZ1_LeakagePower_101_0").toDouble(); + leakage_110 += getGenProperties()->get("INVZ2_LeakagePower_011_0").toDouble(); + + leakage_111 += getGenProperties()->get("INV1_LeakagePower_1").toDouble(); + leakage_111 += getGenProperties()->get("INV2_LeakagePower_1").toDouble(); + leakage_111 += getGenProperties()->get("INVZ1_LeakagePower_011_0").toDouble(); + leakage_111 += getGenProperties()->get("INVZ2_LeakagePower_101_0").toDouble(); + + cache->set(cell_name + "->Leakage->!A!B!S0", leakage_000); + cache->set(cell_name + "->Leakage->!A!BS0", leakage_001); + cache->set(cell_name + "->Leakage->!AB!S0", leakage_010); + cache->set(cell_name + "->Leakage->!ABS0", leakage_011); + cache->set(cell_name + "->Leakage->A!B!S0", leakage_100); + cache->set(cell_name + "->Leakage->A!BS0", leakage_101); + cache->set(cell_name + "->Leakage->AB!S0", leakage_110); + cache->set(cell_name + "->Leakage->ABS0", leakage_111); + Log::printLine(cell_name + "->Leakage->!A!B!S0=" + (String) leakage_000); + Log::printLine(cell_name + "->Leakage->!A!BS0=" + (String) leakage_001); + Log::printLine(cell_name + "->Leakage->!AB!S0=" + (String) leakage_010); + Log::printLine(cell_name + "->Leakage->!ABS0=" + (String) leakage_011); + Log::printLine(cell_name + "->Leakage->A!B!S0=" + (String) leakage_100); + Log::printLine(cell_name + "->Leakage->A!BS0=" + (String) leakage_101); + Log::printLine(cell_name + "->Leakage->AB!S0=" + (String) leakage_110); + Log::printLine(cell_name + "->Leakage->ABS0=" + (String) leakage_111); + + // Cache event energy results + /* + double event_a_flip = 0.0; + event_a_flip += getGenProperties()->get("INVZ1_A_Flip").toDouble(); + cache->set(cell_name + "->Event_A_Flip", event_a_flip); + Log::printLine(cell_name + "->Event_A_Flip=" + (String) event_a_flip); + + double event_b_flip = 0.0; + event_b_flip += getGenProperties()->get("INVZ1_A_Flip").toDouble(); + cache->set(cell_name + "->Event_B_Flip", event_b_flip); + Log::printLine(cell_name + "->Event_B_Flip=" + (String) event_b_flip); + + double event_s0_flip = 0.0; + event_s0_flip += getGenProperties()->get("INV1_A_Flip").toDouble(); + event_s0_flip += getGenProperties()->get("INV1_ZN_Flip").toDouble(); + event_s0_flip += getGenProperties()->get("INVZ1_OE_Flip").toDouble() + getGenProperties()->get("INVZ1_OEN_Flip").toDouble(); + event_s0_flip += getGenProperties()->get("INVZ2_OE_Flip").toDouble() + getGenProperties()->get("INVZ2_OEN_Flip").toDouble(); + cache->set(cell_name + "->Event_S0_Flip", event_s0_flip); + Log::printLine(cell_name + "->Event_S0_Flip=" + (String) event_s0_flip); + + double event_y_flip = 0.0; + event_y_flip += getGenProperties()->get("INVZ1_ZN_Flip").toDouble(); + event_y_flip += getGenProperties()->get("INVZ2_ZN_Flip").toDouble(); + event_y_flip += getGenProperties()->get("INV2_A_Flip").toDouble(); + event_y_flip += getGenProperties()->get("INV2_ZN_Flip").toDouble(); + cache->set(cell_name + "->Event_Y_Flip", event_y_flip); + Log::printLine(cell_name + "->Event_Y_Flip=" + (String) event_y_flip); + + double a_cap = getLoad("INVZ1_CgA")->getLoadCap(); + double b_cap = getLoad("INVZ2_CgA")->getLoadCap(); + double s0_cap = getLoad("INV1_CgA")->getLoadCap() + getLoad("INVZ1_CgOEN")->getLoadCap() + getLoad("INVZ2_CgOE")->getLoadCap(); + double y_ron = getDriver("INV2_RonZN")->getOutputRes(); + */ + // -------------------------------------------------------------------- + + // -------------------------------------------------------------------- + // Get Node capacitances + // -------------------------------------------------------------------- + double a_cap = getNet("A")->getTotalDownstreamCap(); + double b_cap = getNet("B")->getTotalDownstreamCap(); + double s0_cap = getNet("S0")->getTotalDownstreamCap(); + double s0_b_cap = getNet("S0_b")->getTotalDownstreamCap(); + double y_b_cap = getNet("Y_b")->getTotalDownstreamCap(); + double y_cap = getNet("Y")->getTotalDownstreamCap(); + + cache->set(cell_name + "->Cap->A", a_cap); + cache->set(cell_name + "->Cap->B", b_cap); + cache->set(cell_name + "->Cap->S0", s0_cap); + cache->set(cell_name + "->Cap->S0_b", s0_b_cap); + cache->set(cell_name + "->Cap->Y_b", y_b_cap); + cache->set(cell_name + "->Cap->Y", y_cap); + + Log::printLine(cell_name + "->Cap->A=" + (String) a_cap); + Log::printLine(cell_name + "->Cap->B=" + (String) b_cap); + Log::printLine(cell_name + "->Cap->S0=" + (String) s0_cap); + Log::printLine(cell_name + "->Cap->S0_b=" + (String) s0_b_cap); + Log::printLine(cell_name + "->Cap->Y_b=" + (String) y_b_cap); + Log::printLine(cell_name + "->Cap->Y=" + (String) y_cap); + // -------------------------------------------------------------------- + + // -------------------------------------------------------------------- + // Build Internal Delay Model + // -------------------------------------------------------------------- + // Build abstracted timing model + double y_ron = getDriver("INV2_RonZN")->getOutputRes(); + + double a_to_y_delay = 0.0; + a_to_y_delay += getDriver("INVZ1_RonZN")->calculateDelay(); + a_to_y_delay += getDriver("INV2_RonZN")->calculateDelay(); + + double b_to_y_delay = 0.0; + b_to_y_delay += getDriver("INVZ1_RonZN")->calculateDelay(); + b_to_y_delay += getDriver("INV2_RonZN")->calculateDelay(); + + double s0_to_y_delay = 0.0; + s0_to_y_delay += getDriver("INV1_RonZN")->calculateDelay(); + s0_to_y_delay += max(getDriver("INVZ1_RonZN")->calculateDelay(), getDriver("INVZ1_RonZN")->calculateDelay()); + s0_to_y_delay += getDriver("INV2_RonZN")->calculateDelay(); + + cache->set(cell_name + "->DriveRes->Y", y_ron); + cache->set(cell_name + "->Delay->A_to_Y", a_to_y_delay); + cache->set(cell_name + "->Delay->B_to_Y", b_to_y_delay); + cache->set(cell_name + "->Delay->S0_to_Y", s0_to_y_delay); + + Log::printLine(cell_name + "->DriveRes->Y=" + (String) y_ron); + Log::printLine(cell_name + "->Delay->A_to_Y=" + (String) a_to_y_delay); + Log::printLine(cell_name + "->Delay->B_to_Y=" + (String) b_to_y_delay); + Log::printLine(cell_name + "->Delay->S0_to_Y=" + (String) s0_to_y_delay); + // -------------------------------------------------------------------- + + return; + } + +} // namespace DSENT + diff --git a/ext/dsent/model/std_cells/MUX2.h b/ext/dsent/model/std_cells/MUX2.h new file mode 100644 index 000000000..63df6863e --- /dev/null +++ b/ext/dsent/model/std_cells/MUX2.h @@ -0,0 +1,34 @@ +#ifndef __DSENT_MODEL_STD_CELLS_MUX2_H__ +#define __DSENT_MODEL_STD_CELLS_MUX2_H__ + +#include "util/CommonType.h" +#include "model/std_cells/StdCell.h" + +namespace DSENT +{ + class MUX2 : public StdCell + { + // A 2-input MUX standard cell + public: + MUX2(const String& instance_name_, const TechModel* tech_model_); + virtual ~MUX2(); + + public: + // Set a list of properties' name needed to construct model + void initProperties(); + // Cache the standard cell + void cacheStdCell(StdCellLib* cell_lib_, double drive_strength_); + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void evaluateModel(); + virtual void useModel(); + virtual void propagateTransitionInfo(); + + }; // class MUX2 +} // namespace DSENT + +#endif // __DSENT_MODEL_STD_CELLS_MUX2_H__ + diff --git a/ext/dsent/model/std_cells/NAND2.cc b/ext/dsent/model/std_cells/NAND2.cc new file mode 100644 index 000000000..2599f8527 --- /dev/null +++ b/ext/dsent/model/std_cells/NAND2.cc @@ -0,0 +1,267 @@ +#include "model/std_cells/NAND2.h" + +#include <cmath> + +#include "model/PortInfo.h" +#include "model/TransitionInfo.h" +#include "model/EventInfo.h" +#include "model/std_cells/StdCellLib.h" +#include "model/std_cells/CellMacros.h" +#include "model/timing_graph/ElectricalNet.h" +#include "model/timing_graph/ElectricalDriver.h" +#include "model/timing_graph/ElectricalLoad.h" +#include "model/timing_graph/ElectricalDelay.h" + +namespace DSENT +{ + using std::ceil; + using std::max; + + NAND2::NAND2(const String& instance_name_, const TechModel* tech_model_) + : StdCell(instance_name_, tech_model_) + { + initProperties(); + } + + NAND2::~NAND2() + {} + + void NAND2::initProperties() + { + return; + } + + void NAND2::constructModel() + { + // All constructModel should do is create Area/NDDPower/Energy Results as + // well as instantiate any sub-instances using only the hard parameters + + createInputPort("A"); + createInputPort("B"); + createOutputPort("Y"); + + createLoad("A_Cap"); + createLoad("B_Cap"); + createDelay("A_to_Y_delay"); + createDelay("B_to_Y_delay"); + createDriver("Y_Ron", true); + + ElectricalLoad* a_cap = getLoad("A_Cap"); + ElectricalLoad* b_cap = getLoad("A_Cap"); + ElectricalDelay* a_to_y_delay = getDelay("A_to_Y_delay"); + ElectricalDelay* b_to_y_delay = getDelay("B_to_Y_delay"); + ElectricalDriver* y_ron = getDriver("Y_Ron"); + + getNet("A")->addDownstreamNode(a_cap); + getNet("B")->addDownstreamNode(b_cap); + a_cap->addDownstreamNode(a_to_y_delay); + b_cap->addDownstreamNode(b_to_y_delay); + a_to_y_delay->addDownstreamNode(y_ron); + b_to_y_delay->addDownstreamNode(y_ron); + y_ron->addDownstreamNode(getNet("Y")); + + // Create Area result + // Create NDD Power result + createElectricalAtomicResults(); + // Create NAND Event Energy Result + createElectricalEventAtomicResult("NAND2"); + + getEventInfo("Idle")->setStaticTransitionInfos(); + + return; + } + + void NAND2::updateModel() + { + // All updateModel should do is calculate numbers for the Area/NDDPower/Energy + // Results as anything else that needs to be done using either soft or hard parameters + + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Standard cell cache string + String cell_name = "NAND2_X" + (String) drive_strength; + + // Get timing parameters + getLoad("A_Cap")->setLoadCap(cache->get(cell_name + "->Cap->A")); + getLoad("B_Cap")->setLoadCap(cache->get(cell_name + "->Cap->B")); + getDelay("A_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->A_to_Y")); + getDelay("B_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->B_to_Y")); + getDriver("Y_Ron")->setOutputRes(cache->get(cell_name + "->DriveRes->Y")); + + // Set the cell area + getAreaResult("Active")->setValue(cache->get(cell_name + "->Area->Active")); + getAreaResult("Metal1Wire")->setValue(cache->get(cell_name + "->Area->Active")); + + return; + } + + void NAND2::useModel() + { + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Standard cell cache string + String cell_name = "NAND2_X" + (String) drive_strength; + + // Propagate the transition info and get the 0->1 transtion count + propagateTransitionInfo(); + double P_A = getInputPort("A")->getTransitionInfo().getProbability1(); + double P_B = getInputPort("B")->getTransitionInfo().getProbability1(); + double Y_num_trans_01 = getOutputPort("Y")->getTransitionInfo().getNumberTransitions01(); + + // Calculate leakage + double leakage = 0; + leakage += cache->get(cell_name + "->Leakage->!A!B") * (1 - P_A) * (1 - P_B); + leakage += cache->get(cell_name + "->Leakage->!AB") * (1 - P_A) * P_B; + leakage += cache->get(cell_name + "->Leakage->A!B") * P_A * (1 - P_B); + leakage += cache->get(cell_name + "->Leakage->AB") * P_A * P_B; + getNddPowerResult("Leakage")->setValue(leakage); + + // Get capacitances + double y_cap = cache->get(cell_name + "->Cap->Y"); + double y_load_cap = getNet("Y")->getTotalDownstreamCap(); + + // Get VDD + double vdd = getTechModel()->get("Vdd"); + + // Calculate NAND2Event energy + double energy_per_trans_01 = (y_cap + y_load_cap) * vdd * vdd; + getEventResult("NAND2")->setValue(energy_per_trans_01 * Y_num_trans_01); + + return; + } + + void NAND2::propagateTransitionInfo() + { + // Get input signal transition info + const TransitionInfo& trans_A = getInputPort("A")->getTransitionInfo(); + const TransitionInfo& trans_B = getInputPort("B")->getTransitionInfo(); + + double max_freq_mult = max(trans_A.getFrequencyMultiplier(), trans_B.getFrequencyMultiplier()); + const TransitionInfo& scaled_trans_A = trans_A.scaleFrequencyMultiplier(max_freq_mult); + const TransitionInfo& scaled_trans_B = trans_B.scaleFrequencyMultiplier(max_freq_mult); + + double A_prob_00 = scaled_trans_A.getNumberTransitions00() / max_freq_mult; + double A_prob_01 = scaled_trans_A.getNumberTransitions01() / max_freq_mult; + double A_prob_10 = A_prob_01; + double A_prob_11 = scaled_trans_A.getNumberTransitions11() / max_freq_mult; + double B_prob_00 = scaled_trans_B.getNumberTransitions00() / max_freq_mult; + double B_prob_01 = scaled_trans_B.getNumberTransitions01() / max_freq_mult; + double B_prob_10 = B_prob_01; + double B_prob_11 = scaled_trans_B.getNumberTransitions11() / max_freq_mult; + + // Set output transition info + double Y_prob_00 = A_prob_11 * B_prob_11; + double Y_prob_01 = A_prob_11 * B_prob_10 + + A_prob_10 * (B_prob_11 + B_prob_10); + double Y_prob_11 = A_prob_00 + + A_prob_01 * (B_prob_00 + B_prob_10) + + A_prob_10 * (B_prob_00 + B_prob_01) + + A_prob_11 * B_prob_00; + + // Check that probabilities add up to 1.0 with some finite tolerance + ASSERT(LibUtil::Math::isEqual((Y_prob_00 + Y_prob_01 + Y_prob_01 + Y_prob_11), 1.0), + "[Error] " + getInstanceName() + "Output transition probabilities must add up to 1 (" + + (String) Y_prob_00 + ", " + (String) Y_prob_01 + ", " + (String) Y_prob_11 + ")!"); + + // Turn probability of transitions per cycle into number of transitions per time unit + TransitionInfo trans_Y(Y_prob_00 * max_freq_mult, Y_prob_01 * max_freq_mult, Y_prob_11 * max_freq_mult); + getOutputPort("Y")->setTransitionInfo(trans_Y); + return; + } + + void NAND2::cacheStdCell(StdCellLib* cell_lib_, double drive_strength_) + { + // Standard cell cache string + String cell_name = "NAND2_X" + (String) drive_strength_; + + Log::printLine("=== " + cell_name + " ==="); + + // Get parameters + double gate_pitch = cell_lib_->getTechModel()->get("Gate->PitchContacted"); + Map<double>* cache = cell_lib_->getStdCellCache(); + + // Now actually build the full standard cell model + // Create the two input ports + createInputPort("A"); + createInputPort("B"); + createOutputPort("Y"); + + // Adds macros + CellMacros::addNand2(this, "NAND", true, true, true, "A", "B", "Y"); + CellMacros::updateNand2(this, "NAND", drive_strength_); + + // Cache area result + double area = gate_pitch * getTotalHeight() * (1 + getGenProperties()->get("NAND_GatePitches").toDouble()); + cache->set(cell_name + "->Area->Active", area); + Log::printLine(cell_name + "->Area->Active=" + (String) area); + + // -------------------------------------------------------------------- + // Leakage Model Calculation + // -------------------------------------------------------------------- + double leakage_00 = getGenProperties()->get("NAND_LeakagePower_00").toDouble(); + double leakage_01 = getGenProperties()->get("NAND_LeakagePower_01").toDouble(); + double leakage_10 = getGenProperties()->get("NAND_LeakagePower_10").toDouble(); + double leakage_11 = getGenProperties()->get("NAND_LeakagePower_11").toDouble(); + cache->set(cell_name + "->Leakage->!A!B", leakage_00); + cache->set(cell_name + "->Leakage->!AB", leakage_01); + cache->set(cell_name + "->Leakage->A!B", leakage_10); + cache->set(cell_name + "->Leakage->AB", leakage_11); + Log::printLine(cell_name + "->Leakage->!A!B=" + (String) leakage_00); + Log::printLine(cell_name + "->Leakage->!AB=" + (String) leakage_01); + Log::printLine(cell_name + "->Leakage->A!B=" + (String) leakage_10); + Log::printLine(cell_name + "->Leakage->AB=" + (String) leakage_11); + // -------------------------------------------------------------------- + + // Cache event energy results + /* + double event_a_flip = getGenProperties()->get("NAND_A1_Flip").toDouble(); + double event_b_flip = getGenProperties()->get("NAND_A2_Flip").toDouble(); + double event_y_flip = getGenProperties()->get("NAND_ZN_Flip").toDouble(); + + cache->set(cell_name + "->Event_A_Flip", event_a_flip); + cache->set(cell_name + "->Event_B_Flip", event_b_flip); + cache->set(cell_name + "->Event_Y_Flip", event_y_flip); + Log::printLine(cell_name + "->Event_A_Flip=" + (String) event_a_flip); + Log::printLine(cell_name + "->Event_B_Flip=" + (String) event_b_flip); + Log::printLine(cell_name + "->Event_Y_Flip=" + (String) event_y_flip); + */ + // -------------------------------------------------------------------- + // Get Node Capacitances + // -------------------------------------------------------------------- + double a_cap = getNet("A")->getTotalDownstreamCap(); + double b_cap = getNet("B")->getTotalDownstreamCap(); + double y_cap = getNet("Y")->getTotalDownstreamCap(); + + cache->set(cell_name + "->Cap->A", a_cap); + cache->set(cell_name + "->Cap->B", b_cap); + cache->set(cell_name + "->Cap->Y", y_cap); + Log::printLine(cell_name + "->Cap->A=" + (String) a_cap); + Log::printLine(cell_name + "->Cap->B=" + (String) b_cap); + Log::printLine(cell_name + "->Cap->Y=" + (String) y_cap); + // -------------------------------------------------------------------- + + // -------------------------------------------------------------------- + // Build Internal Delay Model + // -------------------------------------------------------------------- + double y_ron = getDriver("NAND_RonZN")->getOutputRes(); + double a_to_y_delay = getDriver("NAND_RonZN")->calculateDelay(); + double b_to_y_delay = getDriver("NAND_RonZN")->calculateDelay(); + + cache->set(cell_name + "->DriveRes->Y", y_ron); + cache->set(cell_name + "->Delay->A_to_Y", a_to_y_delay); + cache->set(cell_name + "->Delay->B_to_Y", b_to_y_delay); + Log::printLine(cell_name + "->DriveRes->Y=" + (String) y_ron); + Log::printLine(cell_name + "->Delay->A_to_Y=" + (String) a_to_y_delay); + Log::printLine(cell_name + "->Delay->B_to_Y=" + (String) b_to_y_delay); + // -------------------------------------------------------------------- + + return; + + } + +} // namespace DSENT + diff --git a/ext/dsent/model/std_cells/NAND2.h b/ext/dsent/model/std_cells/NAND2.h new file mode 100644 index 000000000..75a6436ce --- /dev/null +++ b/ext/dsent/model/std_cells/NAND2.h @@ -0,0 +1,33 @@ +#ifndef __DSENT_MODEL_STD_CELLS_NAND2_H__ +#define __DSENT_MODEL_STD_CELLS_NAND2_H__ + +#include "util/CommonType.h" +#include "model/std_cells/StdCell.h" + +namespace DSENT +{ + class NAND2 : public StdCell + { + public: + NAND2(const String& instance_name_, const TechModel* tech_model_); + virtual ~NAND2(); + + public: + // Set a list of properties' name needed to construct model + void initProperties(); + + // Cache the standard cell + void cacheStdCell(StdCellLib* cell_lib_, double drive_strength_); + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void useModel(); + virtual void propagateTransitionInfo(); + + }; // class NAND2 +} // namespace DSENT + +#endif // __DSENT_MODEL_STD_CELLS_NAND2_H__ + diff --git a/ext/dsent/model/std_cells/NOR2.cc b/ext/dsent/model/std_cells/NOR2.cc new file mode 100644 index 000000000..dd201b956 --- /dev/null +++ b/ext/dsent/model/std_cells/NOR2.cc @@ -0,0 +1,268 @@ +#include "model/std_cells/NOR2.h" + +#include <cmath> + +#include "model/PortInfo.h" +#include "model/TransitionInfo.h" +#include "model/EventInfo.h" +#include "model/std_cells/StdCellLib.h" +#include "model/std_cells/CellMacros.h" +#include "model/timing_graph/ElectricalNet.h" +#include "model/timing_graph/ElectricalDriver.h" +#include "model/timing_graph/ElectricalLoad.h" +#include "model/timing_graph/ElectricalDelay.h" + +namespace DSENT +{ + using std::ceil; + using std::max; + + NOR2::NOR2(const String& instance_name_, const TechModel* tech_model_) + : StdCell(instance_name_, tech_model_) + { + initProperties(); + } + + NOR2::~NOR2() + {} + + void NOR2::initProperties() + { + return; + } + + void NOR2::constructModel() + { + // All constructModel should do is create Area/NDDPower/Energy Results as + // well as instantiate any sub-instances using only the hard parameters + + createInputPort("A"); + createInputPort("B"); + createOutputPort("Y"); + + createLoad("A_Cap"); + createLoad("B_Cap"); + createDelay("A_to_Y_delay"); + createDelay("B_to_Y_delay"); + createDriver("Y_Ron", true); + + ElectricalLoad* a_cap = getLoad("A_Cap"); + ElectricalLoad* b_cap = getLoad("A_Cap"); + ElectricalDelay* a_to_y_delay = getDelay("A_to_Y_delay"); + ElectricalDelay* b_to_y_delay = getDelay("B_to_Y_delay"); + ElectricalDriver* y_ron = getDriver("Y_Ron"); + + getNet("A")->addDownstreamNode(a_cap); + getNet("B")->addDownstreamNode(b_cap); + a_cap->addDownstreamNode(a_to_y_delay); + b_cap->addDownstreamNode(b_to_y_delay); + a_to_y_delay->addDownstreamNode(y_ron); + b_to_y_delay->addDownstreamNode(y_ron); + y_ron->addDownstreamNode(getNet("Y")); + + // Create Area result + // Create NDD Power result + createElectricalAtomicResults(); + // Create NOR Event Energy Result + createElectricalEventAtomicResult("NOR2"); + + getEventInfo("Idle")->setStaticTransitionInfos(); + + return; + } + + void NOR2::updateModel() + { + // All updateModel should do is calculate numbers for the Area/NDDPower/Energy + // Results as anything else that needs to be done using either soft or hard parameters + + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Standard cell cache string + String cell_name = "NOR2_X" + (String) drive_strength; + + // Get timing parameters + getLoad("A_Cap")->setLoadCap(cache->get(cell_name + "->Cap->A")); + getLoad("B_Cap")->setLoadCap(cache->get(cell_name + "->Cap->B")); + getDelay("A_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->A_to_Y")); + getDelay("B_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->B_to_Y")); + getDriver("Y_Ron")->setOutputRes(cache->get(cell_name + "->DriveRes->Y")); + + // Set the cell area + getAreaResult("Active")->setValue(cache->get(cell_name + "->ActiveArea")); + getAreaResult("Metal1Wire")->setValue(cache->get(cell_name + "->ActiveArea")); + + return; + } + + void NOR2::useModel() + { + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Standard cell cache string + String cell_name = "NOR2_X" + (String) drive_strength; + + // Propagate the transition info and get the 0->1 transtion count + propagateTransitionInfo(); + double P_A = getInputPort("A")->getTransitionInfo().getProbability1(); + double P_B = getInputPort("B")->getTransitionInfo().getProbability1(); + double Y_num_trans_01 = getOutputPort("Y")->getTransitionInfo().getNumberTransitions01(); + + // Calculate leakage + double leakage = 0; + leakage += cache->get(cell_name + "->Leakage->!A!B") * (1 - P_A) * (1 - P_B); + leakage += cache->get(cell_name + "->Leakage->!AB") * (1 - P_A) * P_B; + leakage += cache->get(cell_name + "->Leakage->A!B") * P_A * (1 - P_B); + leakage += cache->get(cell_name + "->Leakage->AB") * P_A * P_B; + getNddPowerResult("Leakage")->setValue(leakage); + + // Get VDD + double vdd = getTechModel()->get("Vdd"); + // Get capacitances + double y_cap = cache->get(cell_name + "->Cap->Y"); + double y_load_cap = getNet("Y")->getTotalDownstreamCap(); + + // Calculate NOR2Event energy + double energy_per_trans_01 = (y_cap + y_load_cap) * vdd * vdd; + getEventResult("NOR2")->setValue(energy_per_trans_01 * Y_num_trans_01); + + return; + } + + void NOR2::propagateTransitionInfo() + { + // Get input signal transition info + const TransitionInfo& trans_A = getInputPort("A")->getTransitionInfo(); + const TransitionInfo& trans_B = getInputPort("B")->getTransitionInfo(); + + double max_freq_mult = max(trans_A.getFrequencyMultiplier(), trans_B.getFrequencyMultiplier()); + const TransitionInfo& scaled_trans_A = trans_A.scaleFrequencyMultiplier(max_freq_mult); + const TransitionInfo& scaled_trans_B = trans_B.scaleFrequencyMultiplier(max_freq_mult); + + double A_prob_00 = scaled_trans_A.getNumberTransitions00() / max_freq_mult; + double A_prob_01 = scaled_trans_A.getNumberTransitions01() / max_freq_mult; + double A_prob_10 = A_prob_01; + double A_prob_11 = scaled_trans_A.getNumberTransitions11() / max_freq_mult; + double B_prob_00 = scaled_trans_B.getNumberTransitions00() / max_freq_mult; + double B_prob_01 = scaled_trans_B.getNumberTransitions01() / max_freq_mult; + double B_prob_10 = B_prob_01; + double B_prob_11 = scaled_trans_B.getNumberTransitions11() / max_freq_mult; + + // Set output transition info + double Y_prob_00 = A_prob_00 * B_prob_11 + + A_prob_01 * (B_prob_10 + B_prob_11) + + A_prob_10 * (B_prob_01 + B_prob_11) + + A_prob_11; + double Y_prob_01 = A_prob_00 * B_prob_10 + + A_prob_10 * (B_prob_00 + B_prob_10); + double Y_prob_11 = A_prob_00 * B_prob_00; + + // Check that probabilities add up to 1.0 with some finite tolerance + ASSERT(LibUtil::Math::isEqual((Y_prob_00 + Y_prob_01 + Y_prob_01 + Y_prob_11), 1.0), + "[Error] " + getInstanceName() + "Output transition probabilities must add up to 1 (" + + (String) Y_prob_00 + ", " + (String) Y_prob_01 + ", " + (String) Y_prob_11 + ")!"); + + // Turn probability of transitions per cycle into number of transitions per time unit + TransitionInfo trans_Y(Y_prob_00 * max_freq_mult, Y_prob_01 * max_freq_mult, Y_prob_11 * max_freq_mult); + getOutputPort("Y")->setTransitionInfo(trans_Y); + return; + } + + void NOR2::cacheStdCell(StdCellLib* cell_lib_, double drive_strength_) + { + // Standard cell cache string + String cell_name = "NOR2_X" + (String) drive_strength_; + + Log::printLine("=== " + cell_name + " ==="); + + // Get parameters + double gate_pitch = cell_lib_->getTechModel()->get("Gate->PitchContacted"); + Map<double>* cache = cell_lib_->getStdCellCache(); + + // Now actually build the full standard cell model + // Create the two input ports + createInputPort("A"); + createInputPort("B"); + createOutputPort("Y"); + + // Adds macros + CellMacros::addNor2(this, "NOR", true, true, true, "A", "B", "Y"); + CellMacros::updateNor2(this, "NOR", drive_strength_); + + // Cache area result + double area = gate_pitch * getTotalHeight() * (1 + getGenProperties()->get("NOR_GatePitches").toDouble()); + cache->set(cell_name + "->ActiveArea", area); + Log::printLine(cell_name + "->ActiveArea=" + (String) area); + + // -------------------------------------------------------------------- + // Leakage Model Calculation + // -------------------------------------------------------------------- + double leakage_00 = getGenProperties()->get("NOR_LeakagePower_00").toDouble(); + double leakage_01 = getGenProperties()->get("NOR_LeakagePower_01").toDouble(); + double leakage_10 = getGenProperties()->get("NOR_LeakagePower_10").toDouble(); + double leakage_11 = getGenProperties()->get("NOR_LeakagePower_11").toDouble(); + cache->set(cell_name + "->Leakage->!A!B", leakage_00); + cache->set(cell_name + "->Leakage->!AB", leakage_01); + cache->set(cell_name + "->Leakage->A!B", leakage_10); + cache->set(cell_name + "->Leakage->AB", leakage_11); + Log::printLine(cell_name + "->Leakage->!A!B=" + (String) leakage_00); + Log::printLine(cell_name + "->Leakage->!AB=" + (String) leakage_01); + Log::printLine(cell_name + "->Leakage->A!B=" + (String) leakage_10); + Log::printLine(cell_name + "->Leakage->AB=" + (String) leakage_11); + // -------------------------------------------------------------------- + + /* + // Cache event energy results + double event_a_flip = getGenProperties()->get("NOR_A1_Flip").toDouble(); + double event_b_flip = getGenProperties()->get("NOR_A2_Flip").toDouble(); + double event_zn_flip = getGenProperties()->get("NOR_ZN_Flip").toDouble(); + + cache->set(cell_name + "->Event_A_Flip", event_a_flip); + cache->set(cell_name + "->Event_B_Flip", event_b_flip); + cache->set(cell_name + "->Event_ZN_Flip", event_zn_flip); + Log::printLine(cell_name + "->Event_A_Flip=" + (String) event_a_flip); + Log::printLine(cell_name + "->Event_B_Flip=" + (String) event_b_flip); + Log::printLine(cell_name + "->Event_ZN_Flip=" + (String) event_zn_flip); + */ + + // -------------------------------------------------------------------- + // Get Node Capacitances + // -------------------------------------------------------------------- + // Build abstracted timing model + double a_cap = getNet("A")->getTotalDownstreamCap(); + double b_cap = getNet("B")->getTotalDownstreamCap(); + double y_cap = getNet("Y")->getTotalDownstreamCap(); + + cache->set(cell_name + "->Cap->A", a_cap); + cache->set(cell_name + "->Cap->B", b_cap); + cache->set(cell_name + "->Cap->Y", y_cap); + Log::printLine(cell_name + "->Cap->A_Cap=" + (String) a_cap); + Log::printLine(cell_name + "->Cap->B_Cap=" + (String) b_cap); + Log::printLine(cell_name + "->Cap->Y_Cap=" + (String) y_cap); + // -------------------------------------------------------------------- + + // -------------------------------------------------------------------- + // Build Internal Delay Model + // -------------------------------------------------------------------- + double y_ron = getDriver("NOR_RonZN")->getOutputRes(); + double a_to_y_delay = getDriver("NOR_RonZN")->calculateDelay(); + double b_to_y_delay = getDriver("NOR_RonZN")->calculateDelay(); + + cache->set(cell_name + "->DriveRes->Y", y_ron); + cache->set(cell_name + "->Delay->A_to_Y", a_to_y_delay); + cache->set(cell_name + "->Delay->B_to_Y", b_to_y_delay); + Log::printLine(cell_name + "->DriveRes->Y=" + (String) y_ron); + Log::printLine(cell_name + "->Delay->A_to_Y=" + (String) a_to_y_delay); + Log::printLine(cell_name + "->Delay->B_to_Y=" + (String) b_to_y_delay); + // -------------------------------------------------------------------- + + return; + + } + +} // namespace DSENT + diff --git a/ext/dsent/model/std_cells/NOR2.h b/ext/dsent/model/std_cells/NOR2.h new file mode 100644 index 000000000..b43740717 --- /dev/null +++ b/ext/dsent/model/std_cells/NOR2.h @@ -0,0 +1,33 @@ +#ifndef __DSENT_MODEL_STD_CELLS_NOR2_H__ +#define __DSENT_MODEL_STD_CELLS_NOR2_H__ + +#include "util/CommonType.h" +#include "model/std_cells/StdCell.h" + +namespace DSENT +{ + class NOR2 : public StdCell + { + public: + NOR2(const String& instance_name_, const TechModel* tech_model_); + virtual ~NOR2(); + + public: + // Set a list of properties' name needed to construct model + void initProperties(); + + // Cache the standard cell + void cacheStdCell(StdCellLib* cell_lib_, double drive_strength_); + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void useModel(); + virtual void propagateTransitionInfo(); + + }; // class NOR2 +} // namespace DSENT + +#endif // __DSENT_MODEL_STD_CELLS_NOR2_H__ + diff --git a/ext/dsent/model/std_cells/OR2.cc b/ext/dsent/model/std_cells/OR2.cc new file mode 100644 index 000000000..1271ad091 --- /dev/null +++ b/ext/dsent/model/std_cells/OR2.cc @@ -0,0 +1,279 @@ +#include "model/std_cells/OR2.h" + +#include <cmath> + +#include "model/PortInfo.h" +#include "model/TransitionInfo.h" +#include "model/EventInfo.h" +#include "model/std_cells/StdCellLib.h" +#include "model/std_cells/CellMacros.h" +#include "model/timing_graph/ElectricalNet.h" +#include "model/timing_graph/ElectricalDriver.h" +#include "model/timing_graph/ElectricalLoad.h" +#include "model/timing_graph/ElectricalDelay.h" + +namespace DSENT +{ + using std::max; + + OR2::OR2(const String& instance_name_, const TechModel* tech_model_) + : StdCell(instance_name_, tech_model_) + { + initProperties(); + } + + OR2::~OR2() + {} + + void OR2::initProperties() + { + return; + } + + void OR2::constructModel() + { + createInputPort("A"); + createInputPort("B"); + createOutputPort("Y"); + + createLoad("A_Cap"); + createLoad("B_Cap"); + createDelay("A_to_Y_delay"); + createDelay("B_to_Y_delay"); + createDriver("Y_Ron", true); + + ElectricalLoad* a_cap = getLoad("A_Cap"); + ElectricalLoad* b_cap = getLoad("B_Cap"); + ElectricalDelay* a_to_y_delay = getDelay("A_to_Y_delay"); + ElectricalDelay* b_to_y_delay = getDelay("B_to_Y_delay"); + ElectricalDriver* y_ron = getDriver("Y_Ron"); + + getNet("A")->addDownstreamNode(a_cap); + getNet("B")->addDownstreamNode(b_cap); + a_cap->addDownstreamNode(a_to_y_delay); + b_cap->addDownstreamNode(b_to_y_delay); + a_to_y_delay->addDownstreamNode(y_ron); + b_to_y_delay->addDownstreamNode(y_ron); + y_ron->addDownstreamNode(getNet("Y")); + + // Create Area result + // Create NDD Power result + createElectricalAtomicResults(); + // Create OR Event Energy Result + createElectricalEventAtomicResult("OR2"); + + getEventInfo("Idle")->setStaticTransitionInfos(); + + return; + } + + void OR2::updateModel() + { + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Standard cell cache string + const String& cell_name = "OR2_X" + (String) drive_strength; + + // Get timing parameters + getLoad("A_Cap")->setLoadCap(cache->get(cell_name + "->Cap->A")); + getLoad("B_Cap")->setLoadCap(cache->get(cell_name + "->Cap->B")); + getDelay("A_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->A_to_Y")); + getDelay("B_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->B_to_Y")); + getDriver("Y_Ron")->setOutputRes(cache->get(cell_name + "->DriveRes->Y")); + + // Set the cell area + getAreaResult("Active")->setValue(cache->get(cell_name + "->ActiveArea")); + getAreaResult("Metal1Wire")->setValue(cache->get(cell_name + "->ActiveArea")); + + return; + } + + void OR2::evaluateModel() + { + return; + } + + void OR2::useModel() + { + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Stadard cell cache string + const String& cell_name = "OR2_X" + (String) drive_strength; + + // Propagate the transition info and get the 0->1 transtion count + propagateTransitionInfo(); + double P_A = getInputPort("A")->getTransitionInfo().getProbability1(); + double P_B = getInputPort("B")->getTransitionInfo().getProbability1(); + double Y_num_trans_01 = getOutputPort("Y")->getTransitionInfo().getNumberTransitions01(); + + // Calculate leakage + double leakage = 0; + leakage += cache->get(cell_name + "->Leakage->!A!B") * (1 - P_A) * (1 - P_B); + leakage += cache->get(cell_name + "->Leakage->!AB") * (1 - P_A) * P_B; + leakage += cache->get(cell_name + "->Leakage->A!B") * P_A * (1 - P_B); + leakage += cache->get(cell_name + "->Leakage->AB") * P_A * P_B; + getNddPowerResult("Leakage")->setValue(leakage); + + // Get VDD + double vdd = getTechModel()->get("Vdd"); + + // Get capacitances + double y_b_cap = cache->get(cell_name + "->Cap->Y_b"); + double y_cap = cache->get(cell_name + "->Cap->Y"); + double y_load_cap = getNet("Y")->getTotalDownstreamCap(); + + // Calculate OR2Event energy + double energy_per_trans_01 = (y_b_cap + y_cap + y_load_cap) * vdd * vdd; + getEventResult("OR2")->setValue(energy_per_trans_01 * Y_num_trans_01); + + return; + } + + void OR2::propagateTransitionInfo() + { + // Get input signal transition info + const TransitionInfo& trans_A = getInputPort("A")->getTransitionInfo(); + const TransitionInfo& trans_B = getInputPort("B")->getTransitionInfo(); + + double max_freq_mult = max(trans_A.getFrequencyMultiplier(), trans_B.getFrequencyMultiplier()); + const TransitionInfo& scaled_trans_A = trans_A.scaleFrequencyMultiplier(max_freq_mult); + const TransitionInfo& scaled_trans_B = trans_B.scaleFrequencyMultiplier(max_freq_mult); + + double A_prob_00 = scaled_trans_A.getNumberTransitions00() / max_freq_mult; + double A_prob_01 = scaled_trans_A.getNumberTransitions01() / max_freq_mult; + double A_prob_10 = A_prob_01; + double A_prob_11 = scaled_trans_A.getNumberTransitions11() / max_freq_mult; + double B_prob_00 = scaled_trans_B.getNumberTransitions00() / max_freq_mult; + double B_prob_01 = scaled_trans_B.getNumberTransitions01() / max_freq_mult; + double B_prob_10 = B_prob_01; + double B_prob_11 = scaled_trans_B.getNumberTransitions11() / max_freq_mult; + + // Set output transition info + double Y_prob_00 = A_prob_00 * B_prob_00; + double Y_prob_01 = A_prob_00 * B_prob_01 + + A_prob_01 * (B_prob_00 + B_prob_01); + double Y_prob_11 = A_prob_00 * B_prob_11 + + A_prob_01 * (B_prob_10 + B_prob_11) + + A_prob_10 * (B_prob_01 + B_prob_11) + + A_prob_11; + + // Check that probabilities add up to 1.0 with some finite tolerance + ASSERT(LibUtil::Math::isEqual((Y_prob_00 + Y_prob_01 + Y_prob_01 + Y_prob_11), 1.0), "[Error] " + getInstanceName() + + "Output transition probabilities must add up to 1 (" + (String) Y_prob_00 + ", " + + (String) Y_prob_01 + ", " + (String) Y_prob_11 + ")!"); + + // Turn probability of transitions per cycle into number of transitions per time unit + TransitionInfo trans_Y(Y_prob_00 * max_freq_mult, Y_prob_01 * max_freq_mult, Y_prob_11 * max_freq_mult); + getOutputPort("Y")->setTransitionInfo(trans_Y); + return; + } + + // Creates the standard cell, characterizes and abstracts away the details + void OR2::cacheStdCell(StdCellLib* cell_lib_, double drive_strength_) + { + // Get parameters + double gate_pitch = cell_lib_->getTechModel()->get("Gate->PitchContacted"); + Map<double>* cache = cell_lib_->getStdCellCache(); + + // Stadard cell cache string + const String& cell_name = "OR2_X" + (String) drive_strength_; + + Log::printLine("=== " + cell_name + " ==="); + + // Now actually build the full standard cell model + createInputPort("A"); + createInputPort("B"); + createOutputPort("Y"); + + createNet("Y_b"); + + // Adds macros + CellMacros::addNor2(this, "NOR2", false, true, true, "A", "B", "Y_b"); + CellMacros::addInverter(this, "INV", false, true, "Y_b", "Y"); + + // Update macros + CellMacros::updateNor2(this, "NOR2", drive_strength_ * 0.66); + CellMacros::updateInverter(this, "INV", drive_strength_ * 1.0); + + // Cache area result + double area = 0.0; + area += gate_pitch * getTotalHeight() * 1; + area += gate_pitch * getTotalHeight() * getGenProperties()->get("NOR2_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV_GatePitches").toDouble(); + cache->set(cell_name + "->ActiveArea", area); + Log::printLine(cell_name + "->ActiveArea=" + (String)area); + + // -------------------------------------------------------------------- + // Leakage Model Calculation + // -------------------------------------------------------------------- + // Cache leakage power results (for every single signal combination) + double leakage_00 = 0.0; // !A, !B + double leakage_01 = 0.0; // !A, B + double leakage_10 = 0.0; // A, !B + double leakage_11 = 0.0; // A, B + + leakage_00 += getGenProperties()->get("NOR2_LeakagePower_00").toDouble(); + leakage_00 += getGenProperties()->get("INV_LeakagePower_1").toDouble(); + + leakage_01 += getGenProperties()->get("NOR2_LeakagePower_01").toDouble(); + leakage_01 += getGenProperties()->get("INV_LeakagePower_0").toDouble(); + + leakage_10 += getGenProperties()->get("NOR2_LeakagePower_10").toDouble(); + leakage_10 += getGenProperties()->get("INV_LeakagePower_0").toDouble(); + + leakage_11 += getGenProperties()->get("NOR2_LeakagePower_11").toDouble(); + leakage_11 += getGenProperties()->get("INV_LeakagePower_0").toDouble(); + + cache->set(cell_name + "->Leakage->!A!B", leakage_00); + cache->set(cell_name + "->Leakage->!AB", leakage_01); + cache->set(cell_name + "->Leakage->A!B", leakage_10); + cache->set(cell_name + "->Leakage->AB", leakage_11); + Log::printLine(cell_name + "->Leakage->!A!B=" + (String) leakage_00); + Log::printLine(cell_name + "->Leakage->!AB=" + (String) leakage_01); + Log::printLine(cell_name + "->Leakage->A!B=" + (String) leakage_10); + Log::printLine(cell_name + "->Leakage->AB=" + (String) leakage_11); + // -------------------------------------------------------------------- + + // -------------------------------------------------------------------- + // Get Node Capacitances + // -------------------------------------------------------------------- + double a_cap = getNet("A")->getTotalDownstreamCap(); + double b_cap = getNet("B")->getTotalDownstreamCap(); + double y_b_cap = getNet("Y_b")->getTotalDownstreamCap(); + double y_cap = getNet("Y")->getTotalDownstreamCap(); + + cache->set(cell_name + "->Cap->A", a_cap); + cache->set(cell_name + "->Cap->B", b_cap); + cache->set(cell_name + "->Cap->Y_b", y_b_cap); + cache->set(cell_name + "->Cap->Y", y_cap); + Log::printLine(cell_name + "->Cap->A_Cap=" + (String) a_cap); + Log::printLine(cell_name + "->Cap->B_Cap=" + (String) b_cap); + Log::printLine(cell_name + "->Cap->Y_b_Cap=" + (String) y_b_cap); + Log::printLine(cell_name + "->Cap->Y_Cap=" + (String) y_cap); + // -------------------------------------------------------------------- + + // -------------------------------------------------------------------- + // Build Internal Delay Model + // -------------------------------------------------------------------- + double y_ron = getDriver("INV_RonZN")->getOutputRes(); + double a_to_y_delay = getDriver("NOR2_RonZN")->calculateDelay() + + getDriver("INV_RonZN")->calculateDelay(); + double b_to_y_delay = getDriver("NOR2_RonZN")->calculateDelay() + + getDriver("INV_RonZN")->calculateDelay(); + + cache->set(cell_name + "->DriveRes->Y", y_ron); + cache->set(cell_name + "->Delay->A_to_Y", a_to_y_delay); + cache->set(cell_name + "->Delay->B_to_Y", b_to_y_delay); + Log::printLine(cell_name + "->DriveRes->Y=" + (String) y_ron); + Log::printLine(cell_name + "->Delay->A_to_Y=" + (String) a_to_y_delay); + Log::printLine(cell_name + "->Delay->B_to_Y=" + (String) b_to_y_delay); + // -------------------------------------------------------------------- + + return; + } +} // namespace DSENT + diff --git a/ext/dsent/model/std_cells/OR2.h b/ext/dsent/model/std_cells/OR2.h new file mode 100644 index 000000000..8e08131f1 --- /dev/null +++ b/ext/dsent/model/std_cells/OR2.h @@ -0,0 +1,33 @@ +#ifndef __DSENT_MODEL_STD_CELLS_OR2_H__ +#define __DSENT_MODEL_STD_CELLS_OR2_H__ + +#include "util/CommonType.h" +#include "model/std_cells/StdCell.h" + +namespace DSENT +{ + class OR2 : public StdCell + { + public: + OR2(const String& instance_name_, const TechModel* tech_model_); + virtual ~OR2(); + + public: + // Set a list of properties' name needed to construct model + void initProperties(); + // Cache the standard cell + void cacheStdCell(StdCellLib* cell_lib_, double drive_strength_); + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void evaluateModel(); + virtual void useModel(); + virtual void propagateTransitionInfo(); + + }; // class OR2 +} // namespace DSENT + +#endif // __DSENT_MODEL_STD_CELLS_OR2_H__ + diff --git a/ext/dsent/model/std_cells/StdCell.cc b/ext/dsent/model/std_cells/StdCell.cc new file mode 100644 index 000000000..bc95f97c3 --- /dev/null +++ b/ext/dsent/model/std_cells/StdCell.cc @@ -0,0 +1,71 @@ +#include "model/std_cells/StdCell.h" + +#include "model/timing_graph/ElectricalNet.h" +#include "model/timing_graph/ElectricalDriver.h" +#include "model/timing_graph/ElectricalLoad.h" + +#include <cmath> +#include <algorithm> + +namespace DSENT +{ + StdCell::StdCell(const String& instance_name_, const TechModel* tech_model_) + : ElectricalModel(instance_name_, tech_model_) + { + initParameters(); + initProperties(); + } + + StdCell::~StdCell() + { + + } + + + void StdCell::initParameters() + { + addParameterName("AvailableDrivingStrengths"); + return; + } + + void StdCell::initProperties() + { + addPropertyName("DrivingStrength"); + return; + } + + // Get PMOS to NMOS ratio + double StdCell::getPToNRatio() const + { + return m_p_to_n_ratio_; + } + + void StdCell::setPToNRatio(double p_to_n_ratio_) + { + m_p_to_n_ratio_ = p_to_n_ratio_; + } + + // Get height of the standard cell taken by active transistors + double StdCell::getActiveHeight() const + { + return m_active_height_; + } + + void StdCell::setActiveHeight(double active_height_) + { + m_active_height_ = active_height_; + } + + // Get total height of the standard cell including overheads + double StdCell::getTotalHeight() const + { + return m_total_height_; + } + + void StdCell::setTotalHeight(double total_height_) + { + m_total_height_ = total_height_; + } + +} // namespace DSENT + diff --git a/ext/dsent/model/std_cells/StdCell.h b/ext/dsent/model/std_cells/StdCell.h new file mode 100644 index 000000000..25a65768a --- /dev/null +++ b/ext/dsent/model/std_cells/StdCell.h @@ -0,0 +1,53 @@ +#ifndef __DSENT_MODEL_STD_CELLS_STDCELL_H__ +#define __DSENT_MODEL_STD_CELLS_STDCELL_H__ + +#include "util/CommonType.h" +#include "model/ElectricalModel.h" + +namespace DSENT +{ + class StdCell : public ElectricalModel + { + public: + StdCell(const String& instance_name_, const TechModel* tech_model_); + virtual ~StdCell(); + + public: + // Set a list of parameters needed to construct model + virtual void initParameters(); + // Set a list of properties needed to update model + virtual void initProperties(); + + // Get PMOS to NMOS ratio + double getPToNRatio() const; + void setPToNRatio(double p_to_n_ratio_); + // Get height of the standard cell taken by active transistors + double getActiveHeight() const; + void setActiveHeight(double active_height_); + // Get total height of the standard cell including overheads + double getTotalHeight() const; + void setTotalHeight(double total_height_); + + // Construct the full model of the standard cell and cache + // its contents to use for future copies of the standard cell + virtual void cacheStdCell(StdCellLib* cell_lib_, double drive_strength_) = 0; + + protected: + // Build the model, note that this is only available if the + // standard cell has been cached (via cacheStdCellModel) + virtual void constructModel() = 0; + virtual void updateModel() = 0; + + private: + // The PMOS to NMOS ratio + double m_p_to_n_ratio_; + // The height of the standard cell taken by active transitors + double m_active_height_; + // The total height of the standard cell including overheads + double m_total_height_; + + }; // class StdCell +} // namespace DSENT + +#endif // __DSENT_MODEL_STD_CELLS_STDCELL_H__ + diff --git a/ext/dsent/model/std_cells/StdCellLib.cc b/ext/dsent/model/std_cells/StdCellLib.cc new file mode 100644 index 000000000..dfe32012b --- /dev/null +++ b/ext/dsent/model/std_cells/StdCellLib.cc @@ -0,0 +1,180 @@ +#include "model/std_cells/StdCellLib.h" + +#include <cmath> + +#include "model/std_cells/StdCell.h" +#include "model/std_cells/INV.h" +#include "model/ModelGen.h" + +namespace DSENT +{ + using std::pow; + + StdCellLib::StdCellLib(TechModel* tech_model_) + : m_tech_model_(tech_model_) + { + m_std_cell_cache_ = new Map<double>(); + ASSERT((m_tech_model_ != NULL), "[Error] StdCellLib -> tech_model is NULL"); + createLib(); + } + + StdCellLib::~StdCellLib() + { + delete m_std_cell_cache_; + } + + const TechModel* StdCellLib::getTechModel() const + { + return m_tech_model_; + } + + StdCell* StdCellLib::createStdCell(const String& std_cell_name_, const String& instance_name_) const + { + // Create the standard cell + StdCell* created_cell = ModelGen::createStdCell(std_cell_name_, instance_name_, getTechModel()); + // Grab the variants of each standard cell + String driving_strength_str = getTechModel()->get("StdCell->AvailableSizes"); + // Set library properties for the standard cell + created_cell->setPToNRatio(getPToNRatio()); + created_cell->setActiveHeight(getActiveHeight()); + created_cell->setTotalHeight(getTotalHeight()); + created_cell->setAvailableDrivingStrengths(driving_strength_str); + return created_cell; + } + + // Get PMOS to NMOS ratio + double StdCellLib::getPToNRatio() const + { + return m_p_to_n_ratio_; + } + + void StdCellLib::setPToNRatio(double p_to_n_ratio_) + { + m_p_to_n_ratio_ = p_to_n_ratio_; + } + + // Get height of the standard cell taken by active transistors + double StdCellLib::getActiveHeight() const + { + return m_active_height_; + } + + void StdCellLib::setActiveHeight(double active_height_) + { + m_active_height_ = active_height_; + } + + // Get total height of the standard cell including overheads + double StdCellLib::getTotalHeight() const + { + return m_total_height_; + } + + void StdCellLib::setTotalHeight(double total_height_) + { + m_total_height_ = total_height_; + } + + void StdCellLib::createLib() + { + Log::printLine("Standard cell library creation for tech model " + getTechModel()->get("Name")); + + // Get technology parameters + double nmos_eff_res = getTechModel()->get("Nmos->EffResWidth"); + double pmos_eff_res = getTechModel()->get("Pmos->EffResWidth"); + double gate_min_width = getTechModel()->get("Gate->MinWidth"); + + // Create standard cell common parameters + double pn_ratio = pmos_eff_res / nmos_eff_res; + double nmos_unit_width = gate_min_width; + double pmos_unit_width = gate_min_width * pn_ratio; + + // Derive the height of each cell in the standard cell library, as well as the max Nmos and Pmos widths + double std_cell_total_height = getTechModel()->get("StdCell->Tracks").toDouble() * + (getTechModel()->get("Wire->Metal1->MinWidth").toDouble() + getTechModel()->get("Wire->Metal1->MinSpacing").toDouble()); + double std_cell_active_height = std_cell_total_height / getTechModel()->get("StdCell->HeightOverheadFactor").toDouble(); + + Log::printLine("Standard cell P-to-N ratio (Beta) = " + (String) pn_ratio); + Log::printLine("Standard cell NMOS unit width = " + (String) nmos_unit_width); + Log::printLine("Standard cell PMOS unit width = " + (String) pmos_unit_width); + Log::printLine("Standard cell active height = " + (String) std_cell_active_height); + Log::printLine("Standard cell total height = " + (String) std_cell_total_height); + + setPToNRatio(pn_ratio); + setActiveHeight(std_cell_active_height); + setTotalHeight(std_cell_total_height); + + const vector<String>& cell_sizes = getTechModel()->get("StdCell->AvailableSizes").split("[,]"); + // Create cached standard cells + for (unsigned int i = 0; i < cell_sizes.size(); ++i) + { + StdCell* inv = createStdCell("INV", "CachedINV"); + inv->cacheStdCell(this, cell_sizes[i].toDouble()); + delete inv; + + StdCell* nand2 = createStdCell("NAND2", "CachedNAND2"); + nand2->cacheStdCell(this, cell_sizes[i].toDouble()); + delete nand2; + + StdCell* nor2 = createStdCell("NOR2", "CachedNOR2"); + nor2->cacheStdCell(this, cell_sizes[i].toDouble()); + delete nor2; + + StdCell* mux2 = createStdCell("MUX2", "CachedMUX2"); + mux2->cacheStdCell(this, cell_sizes[i].toDouble()); + delete mux2; + + StdCell* xor2 = createStdCell("XOR2", "CachedXOR2"); + xor2->cacheStdCell(this, cell_sizes[i].toDouble()); + delete xor2; + + StdCell* addf = createStdCell("ADDF", "CachedADDF"); + addf->cacheStdCell(this, cell_sizes[i].toDouble()); + delete addf; + + StdCell* dffq = createStdCell("DFFQ", "CachedDFFQ"); + dffq->cacheStdCell(this, cell_sizes[i].toDouble()); + delete dffq; + + StdCell* latq = createStdCell("LATQ", "CachedLATQ"); + latq->cacheStdCell(this, cell_sizes[i].toDouble()); + delete latq; + + StdCell* or2 = createStdCell("OR2", "CachedOR2"); + or2->cacheStdCell(this, cell_sizes[i].toDouble()); + delete or2; + + StdCell* and2 = createStdCell("AND2", "CachedAND2"); + and2->cacheStdCell(this, cell_sizes[i].toDouble()); + delete and2; + } + + Log::printLine("Standard cell library creation - End"); + return; + } + + StdCellLib* StdCellLib::clone() const + { + StdCellLib* new_lib = new StdCellLib(m_tech_model_); + return new_lib; + } + + const String StdCellLib::genDrivingStrengthString(const vector<double>& driving_strength_) const + { + String ret_str = "["; + for(int i = 0; i < (int)driving_strength_.size() - 1; ++i) + { + ret_str += String(driving_strength_[i]) + ", "; + } + ret_str += String(driving_strength_[driving_strength_.size() - 1]); + ret_str += "]"; + return ret_str; + } + + Map<double>* StdCellLib::getStdCellCache() const + { + return m_std_cell_cache_; + } + +} // namespace DSENT + diff --git a/ext/dsent/model/std_cells/StdCellLib.h b/ext/dsent/model/std_cells/StdCellLib.h new file mode 100644 index 000000000..74c09149e --- /dev/null +++ b/ext/dsent/model/std_cells/StdCellLib.h @@ -0,0 +1,63 @@ +#ifndef __DSENT_MODEL_STD_CELLS_STDCELLLIBS_H__ +#define __DSENT_MODEL_STD_CELLS_STDCELLLIBS_H__ + +#include "util/CommonType.h" + +namespace DSENT +{ + class TechModel; + class StdCell; + class LibertyFile; + + class StdCellLib + { + public: + StdCellLib(TechModel* tech_model_); + ~StdCellLib(); + + public: + // Get the technology model pointer + const TechModel* getTechModel() const; + // Create a standard cell by name and instance name + StdCell* createStdCell(const String& std_cell_name_, const String& instance_name_) const; + + // Get PMOS to NMOS ratio + double getPToNRatio() const; + void setPToNRatio(double p_to_n_ratio_); + // Get height of the standard cell taken by active transistors + double getActiveHeight() const; + void setActiveHeight(double active_height_); + // Get total height of the standard cell including overheads + double getTotalHeight() const; + void setTotalHeight(double total_height_); + // Get the standard cell library cache of values + Map<double>* getStdCellCache() const; + // Create a list of standard cells + void createLib(); + + // Return a copy of this instance + StdCellLib* clone() const; + + private: + // Disabled copy constructor. Use clone to perform copy operation + StdCellLib(const StdCellLib& std_cell_lib_); + // Generate driving strength string + const String genDrivingStrengthString(const vector<double>& driving_strength_) const; + + private: + // Technology model pointer + TechModel* m_tech_model_; + // The PMOS to NMOS ratio + double m_p_to_n_ratio_; + // The height of the standard cell taken by active transitors + double m_active_height_; + // The total height of the standard cell including overheads + double m_total_height_; + // Std cell values cache + Map<double>* m_std_cell_cache_; + + }; // class StdCellLib +} // namespace DSENT + +#endif // __DSENT_MODEL_STD_CELLS_STDCELLLIBS_H__ + diff --git a/ext/dsent/model/std_cells/XOR2.cc b/ext/dsent/model/std_cells/XOR2.cc new file mode 100644 index 000000000..5b57b55e5 --- /dev/null +++ b/ext/dsent/model/std_cells/XOR2.cc @@ -0,0 +1,345 @@ +#include "model/std_cells/XOR2.h" + +#include <cmath> + +#include "model/PortInfo.h" +#include "model/EventInfo.h" +#include "model/TransitionInfo.h" +#include "model/std_cells/StdCellLib.h" +#include "model/std_cells/CellMacros.h" +#include "model/timing_graph/ElectricalNet.h" +#include "model/timing_graph/ElectricalDriver.h" +#include "model/timing_graph/ElectricalLoad.h" +#include "model/timing_graph/ElectricalDelay.h" + +namespace DSENT +{ + using std::ceil; + using std::max; + + XOR2::XOR2(const String& instance_name_, const TechModel* tech_model_) + : StdCell(instance_name_, tech_model_) + { + initProperties(); + } + + XOR2::~XOR2() + {} + + void XOR2::initProperties() + { + return; + } + + void XOR2::constructModel() + { + // All constructModel should do is create Area/NDDPower/Energy Results as + // well as instantiate any sub-instances using only the hard parameters + + createInputPort("A"); + createInputPort("B"); + createOutputPort("Y"); + + createLoad("A_Cap"); + createLoad("B_Cap"); + createDelay("A_to_Y_delay"); + createDelay("B_to_Y_delay"); + createDriver("Y_Ron", true); + + ElectricalLoad* a_cap = getLoad("A_Cap"); + ElectricalLoad* b_cap = getLoad("B_Cap"); + ElectricalDelay* a_to_y_delay = getDelay("A_to_Y_delay"); + ElectricalDelay* b_to_y_delay = getDelay("B_to_Y_delay"); + ElectricalDriver* y_ron = getDriver("Y_Ron"); + + getNet("A")->addDownstreamNode(a_cap); + getNet("B")->addDownstreamNode(b_cap); + a_cap->addDownstreamNode(a_to_y_delay); + b_cap->addDownstreamNode(b_to_y_delay); + a_to_y_delay->addDownstreamNode(y_ron); + b_to_y_delay->addDownstreamNode(y_ron); + y_ron->addDownstreamNode(getNet("Y")); + + // Create Area result + // Create NDD Power result + createElectricalAtomicResults(); + // Create XOR2 Event Energy Result + createElectricalEventAtomicResult("XOR2"); + + getEventInfo("Idle")->setStaticTransitionInfos(); + + return; + } + + void XOR2::updateModel() + { + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Standard cell cache string + String cell_name = "XOR2_X" + (String) drive_strength; + + // Get timing parameters + getLoad("A_Cap")->setLoadCap(cache->get(cell_name + "->Cap->A")); + getLoad("B_Cap")->setLoadCap(cache->get(cell_name + "->Cap->B")); + + getDelay("A_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->A_to_Y")); + getDelay("B_to_Y_delay")->setDelay(cache->get(cell_name + "->Delay->B_to_Y")); + + getDriver("Y_Ron")->setOutputRes(cache->get(cell_name + "->DriveRes->Y")); + + // Set the cell area + getAreaResult("Active")->setValue(cache->get(cell_name + "->ActiveArea")); + getAreaResult("Metal1Wire")->setValue(cache->get(cell_name + "->ActiveArea")); + + return; + } + + void XOR2::evaluateModel() + { + return; + } + + void XOR2::useModel() + { + // Get parameters + double drive_strength = getDrivingStrength(); + Map<double>* cache = getTechModel()->getStdCellLib()->getStdCellCache(); + + // Standard cell cache string + String cell_name = "XOR2_X" + (String) drive_strength; + + // Propagate the transition info and get the 0->1 transtion count + propagateTransitionInfo(); + double P_A = getInputPort("A")->getTransitionInfo().getProbability1(); + double P_B = getInputPort("B")->getTransitionInfo().getProbability1(); + double A_num_trans_01 = getInputPort("A")->getTransitionInfo().getNumberTransitions01(); + double B_num_trans_01 = getInputPort("B")->getTransitionInfo().getNumberTransitions01(); + double Y_num_trans_01 = getOutputPort("Y")->getTransitionInfo().getNumberTransitions01(); + + // Calculate leakage + double leakage = 0; + leakage += cache->get(cell_name + "->Leakage->!A!B") * (1 - P_A) * (1 - P_B); + leakage += cache->get(cell_name + "->Leakage->!AB") * (1 - P_A) * P_B; + leakage += cache->get(cell_name + "->Leakage->A!B") * P_A * (1 - P_B); + leakage += cache->get(cell_name + "->Leakage->AB") * P_A * P_B; + getNddPowerResult("Leakage")->setValue(leakage); + + // Get VDD + double vdd = getTechModel()->get("Vdd"); + + // Get capacitances + double a_b_cap = cache->get(cell_name + "->Cap->A_b"); + double b_b_cap = cache->get(cell_name + "->Cap->B_b"); + double y_cap = cache->get(cell_name + "->Cap->Y"); + double y_load_cap = getNet("Y")->getTotalDownstreamCap(); + + // Calculate XOR Event energy + double xor2_event_result = 0.0; + xor2_event_result += a_b_cap * A_num_trans_01; + xor2_event_result += b_b_cap * B_num_trans_01; + xor2_event_result += (y_cap + y_load_cap) * Y_num_trans_01; + xor2_event_result *= vdd * vdd; + getEventResult("XOR2")->setValue(xor2_event_result); + + return; + } + + void XOR2::propagateTransitionInfo() + { + // Get input signal transition info + const TransitionInfo& trans_A = getInputPort("A")->getTransitionInfo(); + const TransitionInfo& trans_B = getInputPort("B")->getTransitionInfo(); + + double max_freq_mult = max(trans_A.getFrequencyMultiplier(), trans_B.getFrequencyMultiplier()); + const TransitionInfo& scaled_trans_A = trans_A.scaleFrequencyMultiplier(max_freq_mult); + const TransitionInfo& scaled_trans_B = trans_B.scaleFrequencyMultiplier(max_freq_mult); + + + double A_prob_00 = scaled_trans_A.getNumberTransitions00() / max_freq_mult; + double A_prob_01 = scaled_trans_A.getNumberTransitions01() / max_freq_mult; + double A_prob_10 = A_prob_01; + double A_prob_11 = scaled_trans_A.getNumberTransitions11() / max_freq_mult; + double B_prob_00 = scaled_trans_B.getNumberTransitions00() / max_freq_mult; + double B_prob_01 = scaled_trans_B.getNumberTransitions01() / max_freq_mult; + double B_prob_10 = B_prob_01; + double B_prob_11 = scaled_trans_B.getNumberTransitions11() / max_freq_mult; + + // Set output transition info + double Y_prob_00 = A_prob_00 * B_prob_00 + + A_prob_01 * B_prob_01 + + A_prob_10 * B_prob_10 + + A_prob_11 * B_prob_11; + double Y_prob_01 = A_prob_00 * B_prob_01 + + A_prob_01 * B_prob_00 + + A_prob_10 * B_prob_11 + + A_prob_11 * B_prob_10; + double Y_prob_11 = A_prob_00 * B_prob_11 + + A_prob_01 * B_prob_10 + + A_prob_10 * B_prob_01 + + A_prob_11 * B_prob_00; + + // Check that probabilities add up to 1.0 with some finite tolerance + ASSERT(LibUtil::Math::isEqual((Y_prob_00 + Y_prob_01 + Y_prob_01 + Y_prob_11), 1.0), + "[Error] " + getInstanceName() + "Output transition probabilities must add up to 1 (" + + (String) Y_prob_00 + ", " + (String) Y_prob_01 + ", " + (String) Y_prob_11 + ")!"); + + // Turn probability of transitions per cycle into number of transitions per time unit + TransitionInfo trans_Y(Y_prob_00 * max_freq_mult, Y_prob_01 * max_freq_mult, Y_prob_11 * max_freq_mult); + getOutputPort("Y")->setTransitionInfo(trans_Y); + return; + } + + // Creates the standard cell, characterizes and abstracts away the details + void XOR2::cacheStdCell(StdCellLib* cell_lib_, double drive_strength_) + { + // Get parameters + double gate_pitch = cell_lib_->getTechModel()->get("Gate->PitchContacted"); + Map<double>* cache = cell_lib_->getStdCellCache(); + + // Standard cell cache string + String cell_name = "XOR2_X" + (String) drive_strength_; + + Log::printLine("=== " + cell_name + " ==="); + + // Now actually build the full standard cell model + createInputPort("A"); + createInputPort("B"); + createOutputPort("Y"); + + createNet("A_b"); + createNet("B_b"); + + // Adds macros + CellMacros::addInverter(this, "INV1", false, true, "A", "A_b"); + CellMacros::addInverter(this, "INV2", false, true, "B", "B_b"); + CellMacros::addTristate(this, "INVZ1", true, true, true, true, "B", "A", "A_b", "Y"); + CellMacros::addTristate(this, "INVZ2", true, true, true, true, "B_b", "A_b", "A", "Y"); + + // I have no idea how to size each of the parts haha + CellMacros::updateInverter(this, "INV1", drive_strength_ * 0.500); + CellMacros::updateInverter(this, "INV2", drive_strength_ * 0.500); + CellMacros::updateTristate(this, "INVZ1", drive_strength_ * 1.000); + CellMacros::updateTristate(this, "INVZ2", drive_strength_ * 1.000); + + // Cache area result + double area = 0.0; + area += gate_pitch * getTotalHeight() * 1; + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV1_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INV2_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ1_GatePitches").toDouble(); + area += gate_pitch * getTotalHeight() * getGenProperties()->get("INVZ2_GatePitches").toDouble(); + cache->set(cell_name + "->ActiveArea", area); + Log::printLine(cell_name + "->ActiveArea=" + (String) area); + + // -------------------------------------------------------------------- + // Leakage Model Calculation + // -------------------------------------------------------------------- + // Cache leakage power results (for every single signal combination) + double leakage_00 = 0; //!A, !B + double leakage_01 = 0; //!A, B + double leakage_10 = 0; //A, !B + double leakage_11 = 0; //A, B + + //This is so painful... + leakage_00 += getGenProperties()->get("INV1_LeakagePower_0").toDouble(); + leakage_00 += getGenProperties()->get("INV2_LeakagePower_0").toDouble(); + leakage_00 += getGenProperties()->get("INVZ1_LeakagePower_010_0").toDouble(); + leakage_00 += getGenProperties()->get("INVZ2_LeakagePower_101_0").toDouble(); + + leakage_01 += getGenProperties()->get("INV1_LeakagePower_0").toDouble(); + leakage_01 += getGenProperties()->get("INV2_LeakagePower_1").toDouble(); + leakage_01 += getGenProperties()->get("INVZ1_LeakagePower_011_1").toDouble(); + leakage_01 += getGenProperties()->get("INVZ2_LeakagePower_100_1").toDouble(); + + leakage_10 += getGenProperties()->get("INV1_LeakagePower_1").toDouble(); + leakage_10 += getGenProperties()->get("INV2_LeakagePower_0").toDouble(); + leakage_10 += getGenProperties()->get("INVZ1_LeakagePower_100_1").toDouble(); + leakage_10 += getGenProperties()->get("INVZ2_LeakagePower_011_1").toDouble(); + + leakage_11 += getGenProperties()->get("INV1_LeakagePower_1").toDouble(); + leakage_11 += getGenProperties()->get("INV2_LeakagePower_1").toDouble(); + leakage_11 += getGenProperties()->get("INVZ1_LeakagePower_101_0").toDouble(); + leakage_11 += getGenProperties()->get("INVZ2_LeakagePower_010_0").toDouble(); + + cache->set(cell_name + "->Leakage->!A!B", leakage_00); + cache->set(cell_name + "->Leakage->!AB", leakage_01); + cache->set(cell_name + "->Leakage->A!B", leakage_10); + cache->set(cell_name + "->Leakage->AB", leakage_11); + Log::printLine(cell_name + "->Leakage->!A!B=" + (String) leakage_00); + Log::printLine(cell_name + "->Leakage->!AB=" + (String) leakage_01); + Log::printLine(cell_name + "->Leakage->A!B=" + (String) leakage_10); + Log::printLine(cell_name + "->Leakage->AB=" + (String) leakage_11); + // -------------------------------------------------------------------- + + // Cache event energy results + /* + double event_a_flip = 0.0; + event_a_flip += getGenProperties()->get("INV1_A_Flip").toDouble() + getGenProperties()->get("INV1_ZN_Flip").toDouble(); + event_a_flip += getGenProperties()->get("INVZ1_OE_Flip").toDouble() + getGenProperties()->get("INVZ1_OEN_Flip").toDouble(); + event_a_flip += getGenProperties()->get("INVZ2_OE_Flip").toDouble() + getGenProperties()->get("INVZ2_OEN_Flip").toDouble(); + cache->set(cell_name + "->Event_A_Flip", event_a_flip); + Log::printLine(cell_name + "->Event_A_Flip=" + (String) event_a_flip); + + double event_b_flip = 0.0; + event_b_flip += getGenProperties()->get("INV2_A_Flip").toDouble() + getGenProperties()->get("INV2_ZN_Flip").toDouble(); + event_b_flip += getGenProperties()->get("INVZ1_A_Flip").toDouble(); + event_b_flip += getGenProperties()->get("INVZ2_A_Flip").toDouble(); + cache->set(cell_name + "->Event_B_Flip", event_b_flip); + Log::printLine(cell_name + "->Event_B_Flip=" + (String) event_b_flip); + + double event_y_flip = 0.0; + event_y_flip += getGenProperties()->get("INVZ1_ZN_Flip").toDouble(); + event_y_flip += getGenProperties()->get("INVZ2_ZN_Flip").toDouble(); + cache->set(cell_name + "->Event_Y_Flip", event_y_flip); + Log::printLine(cell_name + "->Event_Y_Flip=" + (String) event_y_flip); + */ + + // -------------------------------------------------------------------- + // Get Node Capacitances + // -------------------------------------------------------------------- + // Build abstracted timing model + double a_cap = getNet("A")->getTotalDownstreamCap(); + double b_cap = getNet("B")->getTotalDownstreamCap(); + double a_b_cap = getNet("A_b")->getTotalDownstreamCap(); + double b_b_cap = getNet("B_b")->getTotalDownstreamCap(); + double y_cap = getNet("Y")->getTotalDownstreamCap(); + + cache->set(cell_name + "->Cap->A", a_cap); + cache->set(cell_name + "->Cap->B", b_cap); + cache->set(cell_name + "->Cap->A_b", a_b_cap); + cache->set(cell_name + "->Cap->B_b", b_b_cap); + cache->set(cell_name + "->Cap->Y", y_cap); + Log::printLine(cell_name + "->Cap->A=" + (String) a_cap); + Log::printLine(cell_name + "->Cap->B=" + (String) b_cap); + Log::printLine(cell_name + "->Cap->A=" + (String) a_b_cap); + Log::printLine(cell_name + "->Cap->B=" + (String) b_b_cap); + Log::printLine(cell_name + "->Cap->Y=" + (String) y_cap); + // -------------------------------------------------------------------- + + // -------------------------------------------------------------------- + // Build Internal Delay Model + // -------------------------------------------------------------------- + double y_ron = (getDriver("INVZ1_RonZN")->getOutputRes() + getDriver("INVZ2_RonZN")->getOutputRes()) / 2; + + double a_to_y_delay = 0.0; + a_to_y_delay += getDriver("INV1_RonZN")->calculateDelay(); + a_to_y_delay += max(getDriver("INVZ1_RonZN")->calculateDelay(), getDriver("INVZ2_RonZN")->calculateDelay()); + + double b_to_y_delay = 0.0; + b_to_y_delay += max(getDriver("INVZ1_RonZN")->calculateDelay(), getDriver("INV2_RonZN")->calculateDelay() + getDriver("INVZ2_RonZN")->calculateDelay()); + + cache->set(cell_name + "->DriveRes->Y", y_ron); + cache->set(cell_name + "->Delay->A_to_Y", a_to_y_delay); + cache->set(cell_name + "->Delay->B_to_Y", b_to_y_delay); + Log::printLine(cell_name + "->DriveRes->Y=" + (String) y_ron); + Log::printLine(cell_name + "->Delay->A_to_Y=" + (String) a_to_y_delay); + Log::printLine(cell_name + "->Delay->B_to_Y=" + (String) b_to_y_delay); + // -------------------------------------------------------------------- + + return; + } + +} // namespace DSENT + diff --git a/ext/dsent/model/std_cells/XOR2.h b/ext/dsent/model/std_cells/XOR2.h new file mode 100644 index 000000000..95f9a54b3 --- /dev/null +++ b/ext/dsent/model/std_cells/XOR2.h @@ -0,0 +1,34 @@ +#ifndef __DSENT_MODEL_STD_CELLS_XOR2_H__ +#define __DSENT_MODEL_STD_CELLS_XOR2_H__ + +#include "util/CommonType.h" +#include "model/std_cells/StdCell.h" + +namespace DSENT +{ + class XOR2 : public StdCell + { + public: + XOR2(const String& instance_name_, const TechModel* tech_model_); + virtual ~XOR2(); + + public: + // Set a list of properties' name needed to construct model + void initProperties(); + + // Cache the standard cell + void cacheStdCell(StdCellLib* cell_lib_, double drive_strength_); + + protected: + // Build the model + virtual void constructModel(); + virtual void updateModel(); + virtual void evaluateModel(); + virtual void useModel(); + virtual void propagateTransitionInfo(); + + }; // class XOR2 +} // namespace DSENT + +#endif // __DSENT_MODEL_STD_CELLS_XOR2_H__ + diff --git a/ext/dsent/model/timing_graph/ElectricalDelay.cc b/ext/dsent/model/timing_graph/ElectricalDelay.cc new file mode 100644 index 000000000..e87a77be9 --- /dev/null +++ b/ext/dsent/model/timing_graph/ElectricalDelay.cc @@ -0,0 +1,55 @@ + +#include "model/timing_graph/ElectricalDelay.h" +#include "model/timing_graph/ElectricalLoad.h" + +namespace DSENT +{ + //------------------------------------------------------------------------- + // Electrical Delay + //------------------------------------------------------------------------- + + ElectricalDelay::ElectricalDelay(const String& instance_name_, ElectricalModel* model_) + : ElectricalTimingNode(instance_name_, model_), m_delay_(0.0) + { + + } + + ElectricalDelay::~ElectricalDelay() + { + + } + + void ElectricalDelay::setDelay(double delay_) + { + m_delay_ = delay_; + return; + } + + double ElectricalDelay::getDelay() const + { + return m_delay_; + } + + double ElectricalDelay::calculateDelay() const + { + return m_delay_; + } + + double ElectricalDelay::calculateTransition() const + { + return 1.386 * getMaxUpstreamRes() * getTotalDownstreamCap(); + } + + double ElectricalDelay::getMaxUpstreamRes() const + { + return ElectricalTimingNode::getMaxUpstreamRes(); + } + + double ElectricalDelay::getTotalDownstreamCap() const + { + return ElectricalTimingNode::getTotalDownstreamCap(); + } + +} // namespace DSENT + + diff --git a/ext/dsent/model/timing_graph/ElectricalDelay.h b/ext/dsent/model/timing_graph/ElectricalDelay.h new file mode 100644 index 000000000..d3d3d3a8c --- /dev/null +++ b/ext/dsent/model/timing_graph/ElectricalDelay.h @@ -0,0 +1,43 @@ +#ifndef __DSENT_MODEL_ELECTRICAL_DELAY_H__ +#define __DSENT_MODEL_ELECTRICAL_DELAY_H__ + +#include "util/CommonType.h" +#include "model/timing_graph/ElectricalTimingNode.h" + +namespace DSENT +{ + class ElectricalLoad; + + class ElectricalDelay : public ElectricalTimingNode + { + public: + ElectricalDelay(const String& instance_name_, ElectricalModel* model_); + virtual ~ElectricalDelay(); + + public: + // Specify an ideal delay + void setDelay(double delay_); + // Get the ideal delay + double getDelay() const; + // Calculate delay + double calculateDelay() const; + // Calculate transition + double calculateTransition() const; + // get maximum of upstream drive resistance + double getMaxUpstreamRes() const; + // get total amount of downstream load capacitance + double getTotalDownstreamCap() const; + + private: + // Disable copy constructor + ElectricalDelay(const ElectricalDelay& net_); + + private: + // The amount of ideal delay + double m_delay_; + }; + +} // namespace DSENT + +#endif // __DSENT_MODEL_ELECTRICAL_DELAY_H__ + diff --git a/ext/dsent/model/timing_graph/ElectricalDriver.cc b/ext/dsent/model/timing_graph/ElectricalDriver.cc new file mode 100644 index 000000000..9456ef067 --- /dev/null +++ b/ext/dsent/model/timing_graph/ElectricalDriver.cc @@ -0,0 +1,95 @@ + +#include "model/timing_graph/ElectricalDriver.h" +#include "model/timing_graph/ElectricalNet.h" +#include "model/ElectricalModel.h" + +namespace DSENT +{ + ElectricalDriver::ElectricalDriver(const String& instance_name_, ElectricalModel* model_, bool sizable_) + : ElectricalTimingNode(instance_name_, model_), m_output_res_(0.0), m_sizable_(sizable_) + { + + } + + ElectricalDriver::~ElectricalDriver() + { + + } + + void ElectricalDriver::setOutputRes(double output_res_) + { + m_output_res_ = output_res_; + return; + } + + double ElectricalDriver::getOutputRes() const + { + return m_output_res_; + } + + double ElectricalDriver::calculateDelay() const + { + return 0.693 * m_output_res_ * getTotalDownstreamCap(); + } + + double ElectricalDriver::calculateTransition() const + { + return 1.386 * getMaxUpstreamRes() * getTotalDownstreamCap(); + } + + double ElectricalDriver::getMaxUpstreamRes() const + { + return m_output_res_; + } + + bool ElectricalDriver::isSizable() const + { + return m_sizable_; + } + + bool ElectricalDriver::hasMaxDrivingStrength() const + { + if (!isSizable()) + { + return true; + } + return (getModel() == NULL) || (getModel()->hasMaxDrivingStrength()); + } + + bool ElectricalDriver::hasMinDrivingStrength() const + { + if (!isSizable()) + { + return true; + } + return (getModel() == NULL) || (getModel()->hasMinDrivingStrength()); + } + + void ElectricalDriver::increaseDrivingStrength() + { + ASSERT(isSizable(), "[Error] " + getInstanceName() + + " -> Attempted to size up unsizable driver!"); + if(!hasMaxDrivingStrength()) + { + getModel()->increaseDrivingStrength(); + } + return; + } + + void ElectricalDriver::decreaseDrivingStrength() + { + ASSERT(isSizable(), "[Error] " + getInstanceName() + + " -> Attempted to size down unsizable driver!"); + if(!hasMinDrivingStrength()) + { + getModel()->decreaseDrivingStrength(); + } + return; + } + + bool ElectricalDriver::isDriver() const + { + return true; + } +} // namespace DSENT + diff --git a/ext/dsent/model/timing_graph/ElectricalDriver.h b/ext/dsent/model/timing_graph/ElectricalDriver.h new file mode 100644 index 000000000..604206b5d --- /dev/null +++ b/ext/dsent/model/timing_graph/ElectricalDriver.h @@ -0,0 +1,57 @@ +#ifndef __DSENT_MODEL_ELECTRICAL_DRIVER_H__ +#define __DSENT_MODEL_ELECTRICAL_DRIVER_H__ + +#include "util/CommonType.h" +#include "model/timing_graph/ElectricalTimingNode.h" + +namespace DSENT +{ + class ElectricalModel; + + class ElectricalDriver : public ElectricalTimingNode + { + public: + ElectricalDriver(const String& instance_name_, ElectricalModel* model_, bool sizable_); + virtual ~ElectricalDriver(); + + public: + // Set the output resistance of this driver + void setOutputRes(double output_res_); + // Get the output resistance of this driver + double getOutputRes() const; + // Calculate delay due to total load capacitance + double calculateDelay() const; + // Calculate transition + double calculateTransition() const; + // get maximum of upstream drive resistance + double getMaxUpstreamRes() const; + + // Get whether the driver is sizable + bool isSizable() const; + // Return true if the instance has minimum driving strength + bool hasMinDrivingStrength() const; + // Return true if the instance has maximum driving strength + bool hasMaxDrivingStrength() const; + // Increase driving strength index by 1 + void increaseDrivingStrength(); + // Decrease driving strength index by 1 + void decreaseDrivingStrength(); + + bool isDriver() const; + + private: + // Disable copy constructor + ElectricalDriver(const ElectricalDriver& port_); + + private: + // Name of this instance + String m_instance_name_; + // Output resistance + double m_output_res_; + // Sizable flag + bool m_sizable_; + }; +} // namespace DSENT + +#endif // __DSENT_MODEL_ELECTRICAL_DRIVER_H__ + diff --git a/ext/dsent/model/timing_graph/ElectricalDriverMultiplier.cc b/ext/dsent/model/timing_graph/ElectricalDriverMultiplier.cc new file mode 100644 index 000000000..bf8600fd8 --- /dev/null +++ b/ext/dsent/model/timing_graph/ElectricalDriverMultiplier.cc @@ -0,0 +1,53 @@ + +#include "model/timing_graph/ElectricalDriverMultiplier.h" +#include "model/timing_graph/ElectricalLoad.h" + +namespace DSENT +{ + //------------------------------------------------------------------------- + // Electrical Net + //------------------------------------------------------------------------- + + ElectricalDriverMultiplier::ElectricalDriverMultiplier(const String& instance_name_, ElectricalModel* model_) + : ElectricalTimingNode(instance_name_, model_) + { + + } + + ElectricalDriverMultiplier::~ElectricalDriverMultiplier() + { + + } + + double ElectricalDriverMultiplier::calculateDriveRes( double input_drive_res_) const + { + return input_drive_res_; + } + + double ElectricalDriverMultiplier::calculateDelay() const + { + // This is just a model helper element, it does not contribute delay + return 0; + } + + double ElectricalDriverMultiplier::calculateTransition() const + { + return getMaxUpstreamRes() * getTotalDownstreamCap(); + } + + double ElectricalDriverMultiplier::getTotalDownstreamCap() const + { + // Finds the max of the load caps (as opposed to summing) + double max_cap = 0; + vector<ElectricalTimingNode*>* downstream_nodes = ElectricalTimingNode::getDownstreamNodes(); + for (unsigned int i = 0; i < downstream_nodes->size(); ++i) + { + max_cap = std::max(max_cap, downstream_nodes->at(i)->getTotalDownstreamCap()); + } + + return max_cap; + } + +} // namespace DSENT + + diff --git a/ext/dsent/model/timing_graph/ElectricalDriverMultiplier.h b/ext/dsent/model/timing_graph/ElectricalDriverMultiplier.h new file mode 100644 index 000000000..62b14569f --- /dev/null +++ b/ext/dsent/model/timing_graph/ElectricalDriverMultiplier.h @@ -0,0 +1,42 @@ +#ifndef __DSENT_MODEL_ELECTRICAL_DRIVER_MULTIPLIER_H__ +#define __DSENT_MODEL_ELECTRICAL_DRIVER_MULTIPLIER_H__ + +#include "util/CommonType.h" +#include "model/timing_graph/ElectricalTimingNode.h" + +namespace DSENT +{ + // Simple class that can be used to mimic the presence of multiple drivers + // output drivers (each driving one of the downstream loads) when only one + // such driver has been instantiated (such as models that take advantage of + // bit duplicattion). When the downsream loads differ in load cap, it + // just returns the largest of the caps + class ElectricalDriverMultiplier : public ElectricalTimingNode + { + public: + ElectricalDriverMultiplier(const String& instance_name_, ElectricalModel* model_); + virtual ~ElectricalDriverMultiplier(); + + public: + // Calculate drive resistance of this node; + double calculateDriveRes(double input_drive_res_) const; + // Calculate wiring delay (or net delay) + double calculateDelay() const; + // Calculate transition + double calculateTransition() const; + // get total amount of downstream load capacitance + double getTotalDownstreamCap() const; + + private: + // Disable copy constructor + ElectricalDriverMultiplier(const ElectricalDriverMultiplier& net_); + + private: + // Name of this instance + String m_instance_name_; + }; + +} // namespace DSENT + +#endif // __DSENT_MODEL_ELECTRICAL_DRIVER_MULTIPLIER_H__ + diff --git a/ext/dsent/model/timing_graph/ElectricalLoad.cc b/ext/dsent/model/timing_graph/ElectricalLoad.cc new file mode 100644 index 000000000..a20d6459d --- /dev/null +++ b/ext/dsent/model/timing_graph/ElectricalLoad.cc @@ -0,0 +1,49 @@ + +#include "model/timing_graph/ElectricalLoad.h" +#include "model/ElectricalModel.h" +#include "model/timing_graph/ElectricalDriver.h" + +namespace DSENT +{ + ElectricalLoad::ElectricalLoad(const String& instance_name_, ElectricalModel* model_) + : ElectricalTimingNode(instance_name_, model_), m_load_cap_(0.0) + { + } + + ElectricalLoad::~ElectricalLoad() + { + } + + void ElectricalLoad::setLoadCap(double load_cap_) + { + m_load_cap_ = load_cap_; + return; + } + + double ElectricalLoad::getLoadCap() const + { + return m_load_cap_; + } + + bool ElectricalLoad::isLoad() const + { + return true; + } + + double ElectricalLoad::calculateDelay() const + { + return 0; + } + + double ElectricalLoad::calculateTransition() const + { + return 1.386 * getMaxUpstreamRes() * getTotalDownstreamCap(); + } + + double ElectricalLoad::getTotalDownstreamCap() const + { + return m_load_cap_; + } + +} // namespace DSENT + diff --git a/ext/dsent/model/timing_graph/ElectricalLoad.h b/ext/dsent/model/timing_graph/ElectricalLoad.h new file mode 100644 index 000000000..551eccf85 --- /dev/null +++ b/ext/dsent/model/timing_graph/ElectricalLoad.h @@ -0,0 +1,43 @@ +#ifndef __DSENT_MODEL_ELECTRICAL_LOAD_H__ +#define __DSENT_MODEL_ELECTRICAL_LOAD_H__ + +#include "util/CommonType.h" +#include "model/timing_graph/ElectricalTimingNode.h" + +namespace DSENT +{ + class ElectricalModel; + class ElectricalDriver; + + class ElectricalLoad : public ElectricalTimingNode + { + public: + ElectricalLoad(const String& instance_name_, ElectricalModel* model_); + virtual ~ElectricalLoad(); + + public: + // Set the input capacitance of this input port + void setLoadCap(double load_cap_); + // Get the load capacitance + double getLoadCap() const; + // Get total load capacitance + double getTotalDownstreamCap() const; + // Calculate delay due to total load capacitance + double calculateDelay() const; + // Calculate transition + double calculateTransition() const; + + bool isLoad() const; + + private: + // Disable copy constructor + ElectricalLoad(const ElectricalLoad& load_); + + private: + // Load capacitance + double m_load_cap_; + }; +} // namespace DSENT + +#endif // __DSENT_MODEL_ELECTRICAL_LOAD_H__ + diff --git a/ext/dsent/model/timing_graph/ElectricalNet.cc b/ext/dsent/model/timing_graph/ElectricalNet.cc new file mode 100644 index 000000000..09baa77e5 --- /dev/null +++ b/ext/dsent/model/timing_graph/ElectricalNet.cc @@ -0,0 +1,73 @@ + +#include "model/timing_graph/ElectricalNet.h" +#include "model/timing_graph/ElectricalLoad.h" + +namespace DSENT +{ + //------------------------------------------------------------------------- + // Electrical Net + //------------------------------------------------------------------------- + + ElectricalNet::ElectricalNet(const String& instance_name_, ElectricalModel* model_) + : ElectricalTimingNode(instance_name_, model_), m_distributed_res_(0), m_distributed_cap_(0) + { + + } + + ElectricalNet::~ElectricalNet() + { + + } + + double ElectricalNet::calculateDelay() const + { + // Remember that this is a pi model, delay is distributed cap * distributed_res / 2 + + // distributed res * (other downstream caps) + return 0.693 * (getTotalDownstreamCap() - m_distributed_cap_ / 2) * m_distributed_res_; + } + + double ElectricalNet::calculateTransition() const + { + return 1.386 * getMaxUpstreamRes() * (m_distributed_cap_ * 0.2 + ElectricalTimingNode::getTotalDownstreamCap()); + } + + double ElectricalNet::getMaxUpstreamRes() const + { + return m_distributed_res_ + ElectricalTimingNode::getMaxUpstreamRes(); + } + + double ElectricalNet::getTotalDownstreamCap() const + { + return m_distributed_cap_ + ElectricalTimingNode::getTotalDownstreamCap(); + } + + void ElectricalNet::setDistributedCap(double distributed_cap_) + { + m_distributed_cap_ = distributed_cap_; + return; + } + + void ElectricalNet::setDistributedRes(double distributed_res_) + { + m_distributed_res_ = distributed_res_; + return; + } + + double ElectricalNet::getDistributedCap() const + { + return m_distributed_cap_; + } + + double ElectricalNet::getDistributedRes() const + { + return m_distributed_res_; + } + + bool ElectricalNet::isNet() const + { + return true; + } + +} // namespace DSENT + + diff --git a/ext/dsent/model/timing_graph/ElectricalNet.h b/ext/dsent/model/timing_graph/ElectricalNet.h new file mode 100644 index 000000000..b96bfea91 --- /dev/null +++ b/ext/dsent/model/timing_graph/ElectricalNet.h @@ -0,0 +1,50 @@ +#ifndef __DSENT_MODEL_ELECTRICAL_NET_H__ +#define __DSENT_MODEL_ELECTRICAL_NET_H__ + +#include "util/CommonType.h" +#include "model/timing_graph/ElectricalTimingNode.h" + +namespace DSENT +{ + class ElectricalLoad; + + class ElectricalNet : public ElectricalTimingNode + { + public: + ElectricalNet(const String& instance_name_, ElectricalModel* model_); + virtual ~ElectricalNet(); + + public: + // Set distributed res/cap + void setDistributedRes(double distributed_res_); + void setDistributedCap(double distributed_cap_); + // Get distributed res/cap + double getDistributedRes() const; + double getDistributedCap() const; + // Calculate wiring delay (or net delay) + double calculateDelay() const; + // Calculate transition + double calculateTransition() const; + // get maximum of upstream drive resistance + double getMaxUpstreamRes() const; + // get total amount of downstream load capacitance + double getTotalDownstreamCap() const; + + virtual bool isNet() const; + + private: + // Disable copy constructor + ElectricalNet(const ElectricalNet& net_); + + private: + // Name of this instance + String m_instance_name_; + // Distributed capacitance and resistance of the net + double m_distributed_res_; + double m_distributed_cap_; + }; + +} // namespace DSENT + +#endif // __DSENT_MODEL_ELECTRICAL_NET_H__ + diff --git a/ext/dsent/model/timing_graph/ElectricalTimingNode.cc b/ext/dsent/model/timing_graph/ElectricalTimingNode.cc new file mode 100644 index 000000000..d8b2bfd13 --- /dev/null +++ b/ext/dsent/model/timing_graph/ElectricalTimingNode.cc @@ -0,0 +1,174 @@ + +#include "model/timing_graph/ElectricalTimingNode.h" +#include "model/timing_graph/ElectricalLoad.h" + +namespace DSENT +{ + // Set the optical node initial visited num + const int ElectricalTimingNode::TIMING_NODE_INIT_VISITED_NUM = 0; + + ElectricalTimingNode::ElectricalTimingNode(const String& instance_name_, ElectricalModel* model_) + : m_instance_name_(instance_name_), m_model_(model_), m_false_path_(false), m_crit_path_(-1), + m_visited_num_(ElectricalTimingNode::TIMING_NODE_INIT_VISITED_NUM), m_delay_left_(0.0) + { + m_upstream_nodes_ = new vector<ElectricalTimingNode*>(); + m_downstream_nodes_ = new vector<ElectricalTimingNode*>(); + } + + ElectricalTimingNode::~ElectricalTimingNode() + { + delete m_upstream_nodes_; + delete m_downstream_nodes_; + } + + double ElectricalTimingNode::getMaxUpstreamRes() const + { + double max_res = 0.0; + + for(unsigned int i = 0; i < m_upstream_nodes_->size(); ++i) + { + double res = m_upstream_nodes_->at(i)->getMaxUpstreamRes(); + if(max_res < res) + { + max_res = res; + } + } + return max_res; + } + + double ElectricalTimingNode::getTotalDownstreamCap() const + { + double cap_sum = 0; + + for(unsigned int i = 0; i < m_downstream_nodes_->size(); ++i) + { + cap_sum += m_downstream_nodes_->at(i)->getTotalDownstreamCap(); + } + + return cap_sum; + } + + vector<ElectricalTimingNode*>* ElectricalTimingNode::getUpstreamNodes() const + { + return m_upstream_nodes_; + } + + vector<ElectricalTimingNode*>* ElectricalTimingNode::getDownstreamNodes() const + { + return m_downstream_nodes_; + } + + const String& ElectricalTimingNode::getInstanceName() const + { + return m_instance_name_; + } + + ElectricalModel* ElectricalTimingNode::getModel() + { + return m_model_; + } + + bool ElectricalTimingNode::isDriver() const + { + return false; + } + + bool ElectricalTimingNode::isNet() const + { + return false; + } + + bool ElectricalTimingNode::isLoad() const + { + return false; + } + + + const ElectricalModel* ElectricalTimingNode::getModel() const + { + return (const ElectricalModel*) m_model_; + } + + void ElectricalTimingNode::addDownstreamNode(ElectricalTimingNode* node_) + { + m_downstream_nodes_->push_back(node_); + node_->m_upstream_nodes_->push_back(this); + return; + } + + void ElectricalTimingNode::setFalsePath(bool false_path_) + { + m_false_path_ = false_path_; + return; + } + + bool ElectricalTimingNode::getFalsePath() const + { + return m_false_path_; + } + + + //------------------------------------------------------------------------- + // Functions for delay optimization + //------------------------------------------------------------------------- + // By default, electrical timing nodes cannot be sized up/down + bool ElectricalTimingNode::hasMaxDrivingStrength() const + { + return true; + } + + bool ElectricalTimingNode::hasMinDrivingStrength() const + { + return true; + } + + void ElectricalTimingNode::increaseDrivingStrength() + { + return; + } + + void ElectricalTimingNode::decreaseDrivingStrength() + { + return; + } + //------------------------------------------------------------------------- + + //------------------------------------------------------------------------- + // Node variables for critical path delay calculations + //------------------------------------------------------------------------- + void ElectricalTimingNode::setCritPath(int crit_path_) + { + m_crit_path_ = crit_path_; + return; + } + + int ElectricalTimingNode::getCritPath() const + { + return m_crit_path_; + } + + void ElectricalTimingNode::setVisitedNum(int visited_num_) + { + m_visited_num_ = visited_num_; + return; + } + + int ElectricalTimingNode::getVisitedNum() const + { + return m_visited_num_; + } + + void ElectricalTimingNode::setDelayLeft(double delay_left_) + { + m_delay_left_ = delay_left_; + } + + double ElectricalTimingNode::getDelayLeft() const + { + return m_delay_left_; + } + //------------------------------------------------------------------------- + +} // namespace DSENT + + diff --git a/ext/dsent/model/timing_graph/ElectricalTimingNode.h b/ext/dsent/model/timing_graph/ElectricalTimingNode.h new file mode 100644 index 000000000..01c6497da --- /dev/null +++ b/ext/dsent/model/timing_graph/ElectricalTimingNode.h @@ -0,0 +1,104 @@ +#ifndef __DSENT_MODEL_ELECTRICAL_TIMING_NODE_H__ +#define __DSENT_MODEL_ELECTRICAL_TIMING_NODE_H__ + +#include "util/CommonType.h" + +namespace DSENT +{ + class ElectricalModel; + + class ElectricalTimingNode + { + public: + // The starting visited number flag of all timing nodes + static const int TIMING_NODE_INIT_VISITED_NUM; + + public: + ElectricalTimingNode(const String& instance_name_, ElectricalModel* model_); + virtual ~ElectricalTimingNode(); + + public: + + // Calculate the delay this node contributes + virtual double calculateDelay() const = 0; + // Calculate the transition at this node + virtual double calculateTransition() const = 0; + // get maximum of upstream drive resistance + virtual double getMaxUpstreamRes() const; + // get total amount of downstream load capacitance + virtual double getTotalDownstreamCap() const; + // Return instance name + const String& getInstanceName() const; + // get upstream timing nodes + vector<ElectricalTimingNode*>* getUpstreamNodes() const; + // get downstream timing nodes + vector<ElectricalTimingNode*>* getDownstreamNodes() const; + // Connect a downstream timing node + void addDownstreamNode(ElectricalTimingNode* node_); + // Return the node's parent model + ElectricalModel* getModel(); + const ElectricalModel* getModel() const; + // Set/get false path marker + void setFalsePath(bool false_path_); + bool getFalsePath() const; + + virtual bool isDriver() const; + virtual bool isNet() const; + virtual bool isLoad() const; + + + //----------------------------------------------------------------- + // Functions for delay optimization + //----------------------------------------------------------------- + // Return true if the instance has minimum driving strength + virtual bool hasMinDrivingStrength() const; + // Return true if the instance has maximum driving strength + virtual bool hasMaxDrivingStrength() const; + // Increase driving strength index by 1 + virtual void increaseDrivingStrength(); + // Decrease driving strength index by 1 + virtual void decreaseDrivingStrength(); + //----------------------------------------------------------------- + + //----------------------------------------------------------------- + // Node variables for critical path delay calculations + //----------------------------------------------------------------- + // Critical path marker + void setCritPath(int crit_path_); + int getCritPath() const; + // Visited parity marker + void setVisitedNum(int visited_parity_); + int getVisitedNum() const; + // Delay left in this path + void setDelayLeft(double delay_left_); + double getDelayLeft() const; + //----------------------------------------------------------------- + + + private: + // Disable copy constructor + ElectricalTimingNode(const ElectricalTimingNode& node_); + + private: + // Name of this instance + String m_instance_name_; + // A pointer to the model that contains this node + ElectricalModel* m_model_; + // Upstream electrical nets + vector<ElectricalTimingNode*>* m_upstream_nodes_; + // Downstream electrical nets + vector<ElectricalTimingNode*>* m_downstream_nodes_; + // False path marker + bool m_false_path_; + // Critical path index (to next downstream node) + int m_crit_path_; + // Odd / even path visited (so that you don't have to clear it) + int m_visited_num_; + // The amount of delay left to the end of the timing path + double m_delay_left_; + }; + +} // namespace DSENT + +#endif // __DSENT_MODEL_ELECTRICAL_TIMING_NODE_H__ + diff --git a/ext/dsent/model/timing_graph/ElectricalTimingOptimizer.cc b/ext/dsent/model/timing_graph/ElectricalTimingOptimizer.cc new file mode 100644 index 000000000..dd7b4330a --- /dev/null +++ b/ext/dsent/model/timing_graph/ElectricalTimingOptimizer.cc @@ -0,0 +1,73 @@ +#include "model/timing_graph/ElectricalTimingOptimizer.h" + +#include "model/PortInfo.h" +#include "model/ModelGen.h" +#include "model/std_cells/StdCell.h" +#include "model/std_cells/StdCellLib.h" +#include "model/timing_graph/ElectricalNet.h" +#include "model/timing_graph/ElectricalTimingTree.h" + +namespace DSENT +{ + ElectricalTimingOptimizer::ElectricalTimingOptimizer(const String& instance_name_, const TechModel* tech_model_) + : ElectricalModel(instance_name_, tech_model_), m_model_(NULL) + {} + + ElectricalTimingOptimizer::~ElectricalTimingOptimizer() + {} + + void ElectricalTimingOptimizer::setModel(ElectricalModel* model_) + { + m_model_ = model_; + return; + } + + ElectricalModel* ElectricalTimingOptimizer::getModel() + { + return m_model_; + } + + void ElectricalTimingOptimizer::constructModel() + { + if(getModel() == NULL) + { + return; + } + + const Map<PortInfo*>* port_info = getModel()->getInputs(); + Map<PortInfo*>::ConstIterator it_begin = port_info->begin(); + Map<PortInfo*>::ConstIterator it_end = port_info->end(); + Map<PortInfo*>::ConstIterator it; + + for(it = it_begin; it != it_end; ++it) + { + const String& port_name = it->first; + const PortInfo* port_info = it->second; + StdCell* inv0 = getTechModel()->getStdCellLib()->createStdCell("INV", port_name + "Driver0"); + inv0->construct(); + StdCell* inv1 = getTechModel()->getStdCellLib()->createStdCell("INV", port_name + "Driver1"); + inv1->construct(); + + addSubInstances(inv0, 1.0); + addSubInstances(inv1, 1.0); + + createInputPort(port_name, port_info->getNetIndex()); + createNet(port_name + "Driver0In"); + createNet(port_name + "Driver0Out"); + createNet(port_name + "Driver1Out"); + assignVirtualFanin(port_name + "Driver0In", port_name); + portConnect(inv0, "A", port_name + "Driver0In"); + portConnect(inv0, "Y", port_name + "Driver0Out"); + portConnect(inv1, "A", port_name + "Driver0Out"); + portConnect(inv1, "Y", port_name + "Driver1Out"); + + createNet(port_name + "In", port_info->getNetIndex()); + assignVirtualFanout(port_name + "In", port_name + "Driver1Out"); + + portConnect(getModel(), port_name, port_name + "In"); + } + + return; + } +}// namespace DSENT + diff --git a/ext/dsent/model/timing_graph/ElectricalTimingOptimizer.h b/ext/dsent/model/timing_graph/ElectricalTimingOptimizer.h new file mode 100644 index 000000000..c0c850e0b --- /dev/null +++ b/ext/dsent/model/timing_graph/ElectricalTimingOptimizer.h @@ -0,0 +1,30 @@ +#ifndef __DSENT_MODEL_TIMING_GRAPH_ELECTRICAL_TIMING_OPTIMIZER_H__ +#define __DSENT_MODEL_TIMING_GRAPH_ELECTRICAL_TIMING_OPTIMIZER_H__ + +#include "util/CommonType.h" +#include "model/ElectricalModel.h" + +namespace DSENT +{ + // This model is only used to optimize the timing + class ElectricalTimingOptimizer : public ElectricalModel + { + public: + ElectricalTimingOptimizer(const String& instance_name_, const TechModel* tech_model_); + virtual ~ElectricalTimingOptimizer(); + + public: + void setModel(ElectricalModel* model_); + ElectricalModel* getModel(); + + protected: + // Build the optimizer + virtual void constructModel(); + + private: + ElectricalModel* m_model_; + }; // class ElectricalTimingOptimizer +} // namespace + +#endif // __DSENT_MODEL_TIMING_GRAPH_ELECTRICAL_TIMING_OPTIMIZER_H__ + diff --git a/ext/dsent/model/timing_graph/ElectricalTimingTree.cc b/ext/dsent/model/timing_graph/ElectricalTimingTree.cc new file mode 100644 index 000000000..83d583c53 --- /dev/null +++ b/ext/dsent/model/timing_graph/ElectricalTimingTree.cc @@ -0,0 +1,247 @@ + +#include "model/timing_graph/ElectricalTimingTree.h" + +#include "model/ElectricalModel.h" +#include "model/timing_graph/ElectricalTimingNode.h" +#include "model/timing_graph/ElectricalDriver.h" +#include "model/timing_graph/ElectricalNet.h" + +namespace DSENT +{ + // Initialize the next visited number to be one above the initial number + // used by ElectricalTimingNode + int ElectricalTimingTree::msTreeNum = ElectricalTimingNode::TIMING_NODE_INIT_VISITED_NUM + 1; + + ElectricalTimingTree::ElectricalTimingTree(const String& instance_name_, ElectricalModel* model_) + : m_instance_name_(instance_name_), m_model_(model_) + { + //setTreeNum(1); + } + + ElectricalTimingTree::~ElectricalTimingTree() + { + + } + + const String& ElectricalTimingTree::getInstanceName() const + { + return m_instance_name_; + } + + bool ElectricalTimingTree::performTimingOpt(ElectricalTimingNode* node_, double required_delay_) + { + // Extract the critical path from all timing paths branching out from the starting node + double delay = performCritPathExtract(node_); + double min_delay = delay; + + unsigned int iteration = 0; + unsigned int crit_path_iteration = 0; + unsigned int max_iterations = 8000; //TODO: make this not hard-coded + unsigned int max_iterations_single_crit_path = 400; //TODO: make this not hard-coded + + Log::printLine(getInstanceName() + " -> Beginning Incremental Timing Optimization"); + + // Size up the nodes if timing is not met + while(required_delay_ < delay) + { + Log::printLine(getInstanceName() + " -> Timing Optimization Iteration " + (String) iteration + + ": Required delay = " + (String) required_delay_ + ", Delay = " + + (String) delay + ", Slack = " + (String) (required_delay_ - delay)); + + ElectricalTimingNode* node_for_timing_opt = NULL; + // Go into the less expensive critical path delay calculation + // While the timing is not met for this critical path + while (required_delay_ < delay) + { + // Find the node to optimize timing for, it would return a node to size up + node_for_timing_opt = findNodeForTimingOpt(node_); + // Give up if there are no appropriate nodes to size up or + // max number of iterations has been reached + // Size up the chosen node if there is an appropriate node to size up + if(node_for_timing_opt == NULL || iteration > max_iterations || crit_path_iteration > max_iterations_single_crit_path) + break; + else + node_for_timing_opt->increaseDrivingStrength(); + + // Re-evaluate the delay of the critical path + delay = calculateCritPathDelay(node_); + iteration++; + crit_path_iteration++; + Log::printLine(getInstanceName() + " -> Critical Path Slack: " + (String) (required_delay_ - delay)); + } + // Give up if there are no appropriate nodes to size up or + // max number of iterations has been reached + if (node_for_timing_opt == NULL || iteration > max_iterations || crit_path_iteration > max_iterations_single_crit_path) + break; + + crit_path_iteration = 0; + // Once the critical path timing is met, extract a new critical path from + // all timing paths branching out from the starting node + delay = performCritPathExtract(node_); + min_delay = (min_delay > delay) ? delay : min_delay; + } + Log::printLine(getInstanceName() + " -> Timing Optimization Ended after Iteration: " + (String) iteration + + ": Required delay = " + (String) required_delay_ + ", Delay = " + + (String) delay + ", Slack = " + (String) (required_delay_ - delay)); + + min_delay = (min_delay > delay) ? delay : min_delay; + + // Check if the timing meets the required delay + if(required_delay_ < delay) + { + // Timing not met. Return false and print out a warning message + const String& warning_msg = "[Warning] " + getInstanceName() + " -> Timing not met: Required delay = " + + (String) required_delay_ + ", Minimum Delay = " + (String) min_delay + ", Slack = " + + (String) (required_delay_ - delay); + Log::printLine(std::cerr, warning_msg); + return false; + } + return true; + } + //------------------------------------------------------------------------- + // Extract Crit Path Delay (and marks the crit path) + //------------------------------------------------------------------------- + double ElectricalTimingTree::performCritPathExtract(ElectricalTimingNode* node_) + { + setTreeNum(getTreeNum() + 1); + return extractCritPathDelay(node_); + } + + double ElectricalTimingTree::extractCritPathDelay(ElectricalTimingNode* node_) + { + //TODO: Replace with a stack data structure instead of recursion to prevent + //stack overflow problems with long chains of logic (4000+ nodes) and/or better + //performance. Nvm, stack data structure version seems to run much slower + + // If the node has already been visited, return the delay! + if (node_->getVisitedNum() == getTreeNum()) + return node_->getDelayLeft(); + // If the node has been marked as a false path, return 0.0 + else if (node_->getFalsePath()) + return 0.0; + + // Set the new parity for this node + node_->setVisitedNum(getTreeNum()); + node_->setDelayLeft(0.0); + + double max_delay = 0; + double current_delay = 0; + + // Traverse downstream nodes to calculate the delay through each downstream path + vector<ElectricalTimingNode*>* d_nodes = node_->getDownstreamNodes(); + for (unsigned int i = 0; i < d_nodes->size(); ++i) + { + current_delay = extractCritPathDelay(d_nodes->at(i)); + // Update the critical path + if (current_delay > max_delay) + { + node_->setCritPath(i); + max_delay = current_delay; + } + } + // Calculate the delay left from this node + double delay_left = node_->calculateDelay() + max_delay; + node_->setDelayLeft(delay_left); + + return delay_left; + + } + + double ElectricalTimingTree::calculateCritPathDelay(ElectricalTimingNode* node_) const + { + // Simplest case where theres nothing to optimize + if (node_ == NULL) + return 0.0; + + double delay = 0.0; + int crit_path = 0; + + // Traverse the critical path and sum up delays + while (crit_path >= 0) + { + delay += node_->calculateDelay(); + //Move on to the next node in the critical path + crit_path = node_->getCritPath(); + if (crit_path >= 0) + node_ = node_->getDownstreamNodes()->at(crit_path); + } + return delay; + } + //------------------------------------------------------------------------- + + //------------------------------------------------------------------------- + // Find Worst Slew Helpers + //------------------------------------------------------------------------- + ElectricalTimingNode* ElectricalTimingTree::findNodeForTimingOpt(ElectricalTimingNode* node_) const + { + // Simplest case where theres nothing to optimize + if (node_ == NULL) + return NULL; + + double max_transition_ratio = -10.0; + double current_transition_ratio = 0.0; + double previous_transition = 1e3 * node_->getTotalDownstreamCap(); + double current_transition = 0.0; + ElectricalTimingNode* worst = NULL; + int crit_path = 0; + + // Find the node with the highest max_transition_ratio to return + while (crit_path >= 0) + { + current_transition = node_->calculateDelay(); + + //If the node is not yet at max size, it is a potential choice for size up + if (!node_->hasMaxDrivingStrength()) + { + current_transition_ratio = current_transition / previous_transition; + + if (current_transition_ratio > max_transition_ratio) + { + worst = node_; + max_transition_ratio = current_transition_ratio; + } + } + + if (node_->isDriver()) + previous_transition = 0.0; + previous_transition += current_transition; + + //Move on to the next node in the critical path + crit_path = node_->getCritPath(); + + if (crit_path >= 0) + node_ = node_->getDownstreamNodes()->at(crit_path); + } + + return worst; + } + //------------------------------------------------------------------------- + + double ElectricalTimingTree::calculateNodeTransition(ElectricalTimingNode* node_) const + { + return node_->calculateTransition(); + } + + ElectricalTimingTree::ElectricalTimingTree(const ElectricalTimingTree& /* graph_ */) + { + // Disabled + } + + ElectricalModel* ElectricalTimingTree::getModel() + { + return m_model_; + } + + void ElectricalTimingTree::setTreeNum(int tree_num_) + { + msTreeNum = tree_num_; + return; + } + + int ElectricalTimingTree::getTreeNum() + { + return msTreeNum; + } + +} // namespace DSENT + diff --git a/ext/dsent/model/timing_graph/ElectricalTimingTree.h b/ext/dsent/model/timing_graph/ElectricalTimingTree.h new file mode 100644 index 000000000..4dfbff8a7 --- /dev/null +++ b/ext/dsent/model/timing_graph/ElectricalTimingTree.h @@ -0,0 +1,73 @@ +#ifndef __DSENT_MODEL_ELECTRICAL_TIMING_TREE_H__ +#define __DSENT_MODEL_ELECTRICAL_TIMING_TREE_H__ + +#include <vector> + +#include "util/CommonType.h" +#include "model/timing_graph/ElectricalTimingNode.h" + +namespace DSENT +{ + using std::vector; + + class ElectricalDriver; + + class ElectricalTimingTree + { + public: + // The visited number for the next timing run. This needs to be + // global because several timing trees may be created to evaluate + // a single timing path, causing problems + static int msTreeNum; + + public: + // Construct timing tree that watches over model_ + ElectricalTimingTree(const String& instance_name_, ElectricalModel* model_); + ~ElectricalTimingTree(); + + public: + // Get tree name + const String& getInstanceName() const; + + // A wrapper for extractCritPathDelay + // Update the tree num before do extract critical path delay recursively + double performCritPathExtract(ElectricalTimingNode* node_); + // Calculate the delay of the marked critical path from a starting node + double calculateCritPathDelay(ElectricalTimingNode* node_) const; + // Calculate the transition at a node + double calculateNodeTransition(ElectricalTimingNode* node_) const; + // Returns the optimal node to optimize timing (by sizing up) in the critical + // path to reduce critical path delay + ElectricalTimingNode* findNodeForTimingOpt(ElectricalTimingNode* node_) const; + // Perform incremental timing optimization to guarantee that all timing paths from a + // starting node meets a required delay + // Return false if the timing optimization fails to meet the required delay + bool performTimingOpt(ElectricalTimingNode* node_, double required_delay_); + + // Return the model + ElectricalModel* getModel(); + + private: + // Disable the use of copy constructor + ElectricalTimingTree(const ElectricalTimingTree& graph_); + + // Recursively calculate delay from a starting node, finding and marking the + // critical path along the way and returns the delay of the critical path + double extractCritPathDelay(ElectricalTimingNode* node_); + + public: + // Set the sequence number of the timing tree + static void setTreeNum(int tree_num_); + static int getTreeNum(); + + private: + // Name of the timing tree + const String m_instance_name_; + // A pointer to the model that contains this node + ElectricalModel* m_model_; + + }; // class ElectricalTimingTree +} // namespace DSENT + +#endif // __DSENT_MODEL_ELECTRICAL_TIMING_TREE_H__ + |