// OpenSTA, Static Timing Analyzer
// Copyright (c) 2026, Parallax Software, Inc.
// 
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// 
// The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software.
// 
// Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 
// This notice may not be removed or altered from any source distribution.

#include "TimingRole.hh"

#include "MinMax.hh"

namespace sta {

TimingRoleMap TimingRole::timing_roles_;
const TimingRole TimingRole::wire_("wire", false, false, false, nullptr, nullptr, 0);
const TimingRole TimingRole::combinational_("combinational", true, false,  false,
                                            nullptr, nullptr, 1);
const TimingRole TimingRole::tristate_enable_("tristate enable",
                                              true, false, false,
                                              nullptr, nullptr, 2);
const TimingRole TimingRole::tristate_disable_("tristate disable",
                                               true, false, false,
                                               nullptr, nullptr, 3);
const TimingRole TimingRole::reg_clk_q_("Reg Clk to Q", true, false, false,
                                        nullptr, nullptr, 4);
const TimingRole TimingRole::reg_set_clr_("Reg Set/Clr", true, false, false,
                                          nullptr, nullptr, 5);
const TimingRole TimingRole::latch_en_q_("Latch En to Q", true, false, false,
                                         nullptr, TimingRole::regClkToQ(), 6);
const TimingRole TimingRole::latch_d_q_("Latch D to Q", true, false, false,
                                        nullptr, nullptr, 7);
const TimingRole TimingRole::sdf_iopath_("sdf IOPATH", true, false, false,
                                         nullptr, nullptr, 8);
const TimingRole TimingRole::setup_("setup", false, true, false,
                                    MinMax::max(), nullptr, 9);
const TimingRole TimingRole::hold_("hold", false, true, false,
                                   MinMax::min(), nullptr, 10);
const TimingRole TimingRole::recovery_("recovery", false, true, false,
                                       MinMax::max(), TimingRole::setup(), 11);
const TimingRole TimingRole::removal_("removal", false, true, false,
                                      MinMax::min(), TimingRole::hold(), 12);
const TimingRole TimingRole::width_("width", false, true, false,
                                    nullptr, nullptr, 13);
const TimingRole TimingRole::period_("period", false, true, false,
                                     nullptr, nullptr, 14);
const TimingRole TimingRole::skew_("skew", false, true, false,
                                   nullptr, nullptr, 15);
const TimingRole TimingRole::nochange_("nochange", true, false, false,
                                       nullptr, nullptr, 16);
const TimingRole TimingRole::output_setup_("output setup", false, true, false,
                                           MinMax::max(), TimingRole::setup(), 17);
const TimingRole TimingRole::output_hold_("output hold", false, true, false,
                                          MinMax::min(), TimingRole::hold(), 18);
const TimingRole TimingRole::gated_clk_setup_("clock gating setup",
                                              false, true, false,
                                              MinMax::max(), TimingRole::setup(),19);
const TimingRole TimingRole::gated_clk_hold_("clock gating hold", false, true, false,
                                             MinMax::min(), TimingRole::hold(),20);
const TimingRole TimingRole::latch_setup_("latch setup", false, true, false,
                                          MinMax::max(), TimingRole::setup(),21);
const TimingRole TimingRole::latch_hold_("latch hold", false, true, false,
                                         MinMax::min(), TimingRole::hold(),22);
const TimingRole TimingRole::data_check_setup_("data check setup",
                                               false, true, false,
                                               MinMax::max(),TimingRole::setup(),23);
const TimingRole TimingRole::data_check_hold_("data check hold", false, true, false,
                                              MinMax::min(), TimingRole::hold(), 24);
const TimingRole TimingRole::non_seq_setup_("non-sequential setup", false, true, true,
                                            MinMax::max(), TimingRole::setup(), 25);
const TimingRole TimingRole::non_seq_hold_("non-sequential hold", false, true, true,
                                           MinMax::min(), TimingRole::hold(), 26);
const TimingRole TimingRole::clock_tree_path_min_("min clock tree path", false, false,
                                                  false, MinMax::min(), nullptr, 27);
const TimingRole TimingRole::clock_tree_path_max_("max clock tree path", false, false,
                                                  false, MinMax::max(), nullptr, 28);
const TimingRole TimingRole::port_delay_ref_pin_("port delay ref pin", false, false,
                                                 false, nullptr, nullptr, 29);

TimingRole::TimingRole(const char *name,
                       bool is_sdf_iopath,
                       bool is_timing_check,
                       bool is_non_seq_check,
                       const MinMax *path_min_max,
                       const TimingRole *generic_role,
                       int index) :
  name_(name),
  is_timing_check_(is_timing_check),
  is_sdf_iopath_(is_sdf_iopath),
  is_non_seq_check_(is_non_seq_check),
  generic_role_(generic_role),
  index_(index),
  path_min_max_(path_min_max)
{
  timing_roles_[name] = this;
}

const TimingRole *
TimingRole::find(const char *name)
{
  return timing_roles_[name];
}

const TimingRole *
TimingRole::sdfRole() const
{
  if (is_sdf_iopath_)
    return &sdf_iopath_;
  else
    return this;
}

const TimingRole *
TimingRole::genericRole() const
{
  if (generic_role_ == nullptr)
    return this;
  else
    return generic_role_;
}

const EarlyLate *
TimingRole::tgtClkEarlyLate() const
{
  return path_min_max_->opposite();
}

bool
TimingRole::isWire() const
{
  return this == &wire_;
}

bool
TimingRole::isAsyncTimingCheck() const
{
  return this == &recovery_
    || this == &removal_;
}

bool
TimingRole::isDataCheck() const
{
  return this == &data_check_setup_
    || this == &data_check_hold_;
}

bool
TimingRole::isLatchDtoQ() const
{
  return this == &latch_d_q_;
}

bool
TimingRole::isLatchEnToQ() const
{
  return this == &latch_en_q_;
}

bool
TimingRole::isTimingCheckBetween() const
{
  return is_timing_check_
    && this != &width_
    && this != &period_;
}

bool
TimingRole::less(const TimingRole *role1,
                 const TimingRole *role2)
{
  return role1->index() < role2->index();
}

} // namespace sta
