Coolquest, Inc. Home Products Support About Contact
cbold_logo_gif C++BOLD Example Design: IROD cbold_logo_gif

Design Home <<  File View  >> Class View Output (partial) Parts Library Examples Home

 

// THIS FILE IS IN THE PUBLIC DOMAIN.
// IT IS PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT
// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 
#ifndef _IrodPropH_
#define _IrodPropH_
 
#include "cb_prop.h"
#include "monopins.h"  // CP_MONOPIN25 is identified via RTTI
 
 
class CR_MatchClock : public TProperty {
private:
  char* ClassName;  // instances having the same class name act logically as one property
public:
// custom members
  int LongLengthMatchTolerance;   // tolerance in mils, set to <= 0 to turn off long length matching
  int ShortMaxLength;             // max length in mils of short stubs (this is the relaxed rule after routing is complete)
  char* GetClassName() { return ClassName; }
 
// standard members
  CR_MatchClock( char* aClassName = 0 ) {
    ClassName = aClassName;
    LongLengthMatchTolerance = 2000;
    ShortMaxLength = 2000;
  }
  virtual void Associate( TPortRange& aPortRange ) {
    TPart* Part = dynamic_cast<TPart*>( aPortRange.GetPort()->GetOwner() );
    if ( Part == 0 )  BEGERR << "P_MatchClock may only be associated with a part's port or range thereof" << ENDERR;
    associate( aPortRange );
  }
  // these Associate()'s are optional, but declaring them avoids compiler warning about hiding virtual function
  virtual void Associate(     TModPar& aModPar           ) { illegal( aModPar        ); }
  virtual void Associate( TBundle& aBundle       ) { illegal( aBundle    ); }
  virtual void Associate( char* aName, TModule* aModule  ) { illegal( aName, aModule ); }
 
};
 
 
class TGenLayoutScript {
private:
                             // convenience variables
  ofstream      Fromtos;     // destination file for fromto definitions
  ofstream      TightRules;  // Tight = tight tolerance which is typically not achievable
  ofstream      LooseRules;  // Loose = relaxed tolerance for final conflict reporting
  TRootModule*  Root;        // root of design
  TNetList*     NL;          // netlist for design
  unsigned      PropCount;   // count of properties in the global property list
 
  void OutPS( ostream& Dest, TPinSpec PS ) {
    TPort* Port = PS.GetPort();
    int Index   = PS.GetIndex();
 
    TPart* OP = dynamic_cast<TPart*>( Port->GetOwner() );
    if ( !OP )                  BEGERR << "TGenLayoutScript encountered non-part port owner " << OP << ENDERR;
    if ( Port->MultiPinNode() ) BEGERR << "TGenLayoutScript encountered multi-pin node "      << PS << ENDERR;
    Dest << OP->GetReferenceDesignator();
    Dest << '-' << Port->GetPin( Index );
  }
 
                        // one function for each part of the script
  void MatchClock() {
 
    int       ClockCount   = 0;    // counter used to create unique names (class, long group, and short group)
    int       MpCount      = 0;    // MonoPins, one per driver
    const char* ClassBase   = "CLK_CNET_CLASS_";               // base of unique names
    const char* LongBase    = "CLK_LONG_GROUP_";
    const char* ShortBase   = "CLK_SHRT_GROUP_";
                                    // list of MatchClock properties
    vector<CR_MatchClock*> MCV_CC;   // as associated with clocks (ClockCount)
    vector<CR_MatchClock*> MCV_VC;   // as associated with MonoPins (MpCount)
 
// spp_clocks.do calls the four do files created by this funtion
// spp_clocks.do sets units to mils
 
    for ( unsigned prop = 0; prop < PropCount; ++ prop ) {   // for each property in global list
      TProperty* P = Root->Properties.GetProperty( prop );
      CR_MatchClock* MC = dynamic_cast<CR_MatchClock*>( P );
      if ( MC ) {
        if ( MC->GetClassName() != 0 )  BEGERR << "ClassName feature not yet implemented for CR_MatchClock" << ENDERR;
 
        MCV_CC.push_back( MC );  // save for use below
        Fromtos << "\n";
        Fromtos << "\ndefine (class " << ClassBase << ClockCount << ")";   // add nets to class later
        Fromtos << "\ndefine (group " << LongBase  << ClockCount << ")";   // add fromto's to group later
 
        for ( unsigned pr = 0; pr < MC->GetPortRangeCount(); ++ pr ) {  // for each port range associated with the property
          Fromtos << "\n";
          TPortRange PortRange = MC->GetPortRange( pr );
          for ( int i = PortRange.GetMinRange(); i <= PortRange.GetMaxRange(); ++ i ) {  // for each pin in port range
            TPinSpec SourcePS = TPinSpec( PortRange.GetPort(), i );
            TNet* N = NL->PinInNetList( SourcePS );
            if ( N == 0 )                            BEGERR << "TGenLayoutScript could not find pin " << SourcePS << " in netlist" << ENDERR;
            if ( N->DesignatorEquals( NoConnect ) )            continue;  // >>> ignore pins on no-connect net
            if ( strncmp( "MEAS_", N->GetString(), 5 ) == 0 )  continue;  // >>> ignore pins on nets starting with "MEAS_"
            if ( strncmp( "MPYI_", N->GetString(), 4 ) == 0 )  continue;  // >>> ignore pins on nets starting with "MPYI_"
 
            int PS_Count = N->GetPinSpecCount();
            int PinCount = N->GetPartPinSpecCount();
            if ( PinCount < 2  )                    continue;  // >>> ignore single-node nets
 
            TPinSpec* MonoPSP = 0;                  // PinSpec for monopin, if any
            for ( int p = 0; p < PS_Count; ++p ) {  // find PinSpec for monopin, if any
              TPinSpec* PSP = N->GetPinSpec( p );
              if ( typeid( *PSP->GetPort()->GetOwner() )  == typeid ( CP_MONOPIN25 ) ) {   // >>> alternative:  identify monopin by counting its pins
                MonoPSP = PSP;
              }
            }
 
            if ( PinCount == 2 ) {                          // >>> two-node nets get no far-end cluster
              if ( MonoPSP != 0 )
                BEGERR << "TGenLayoutScript::MatchClock(): two-node net " << N << "must contain no MonoPin" << ENDERR;
              Fromtos << "\ndefine (class " << ClassBase << ClockCount << "(add_net " << N << "))";
              Fromtos << "\ndefine (group " << LongBase  << ClockCount << "(add_fromto (fromto  ";
                  OutPS( Fromtos, SourcePS );
                  Fromtos << " ";
                  for ( int p = 0; p < PS_Count; ++ p ) {  // for each PinSpec
                    TPinSpec LoadPS = *N->GetPinSpec( p );
                    if ( !LoadPS.OwnerIsPart() )  continue;
                    if (  LoadPS == SourcePS   )  continue;
                    OutPS( Fromtos, LoadPS );
                  }
                  Fromtos << ")))";
              Fromtos << "\n#***** warning:  Net " << N << " has fewer than two load pins.\n";
              continue;
            }
 
            if ( MonoPSP == 0 )
              BEGERR << "TGenLayoutScript::MatchClock() found no MonoPin connected to net " << N << ENDERR;
 
            TPinSpec MonoPS = *MonoPSP;
            if ( MonoPS == SourcePS )
              BEGERR << "TGenLayoutScript::MatchClock():  CR_MatchClock must be associated with the source pin of net " << N << ", not the MonoPin" << ENDERR;
 
// nets with >= two nodes:
            Fromtos << "\ndefine (class " << ClassBase << ClockCount << "(add_net " << N << "))";
            Fromtos << "\ndefine (group " << LongBase  << ClockCount << "(add_fromto (fromto ";
                OutPS( Fromtos, SourcePS );
                Fromtos << " ";
                OutPS( Fromtos, MonoPS );
                Fromtos << ")))";
 
            Fromtos << "\ndefine (group " << ShortBase  << MpCount;
            Fromtos << " (add_fromto";
            for ( int p = 0; p < PS_Count; ++ p ) {  // for each PinSpec in the net
              TPinSpec LoadPS = *N->GetPinSpec( p );
              if ( !LoadPS.OwnerIsPart() )  continue;
              if ( LoadPS == SourcePS    )  continue;
              if ( LoadPS == MonoPS      )  continue;
              Fromtos << "\n(fromto ";
              OutPS( Fromtos, MonoPS );
              Fromtos << " ";
              OutPS( Fromtos, LoadPS );
              Fromtos << ")";
            }
            Fromtos << "\n))";
 
            MCV_VC.push_back( MC );  // save for use below
            MpCount++;
          }
        }
        ++ ClockCount;
      }
    }
    if ( ClockCount == 0 )  return;
 
// assign rules to classes
    for ( int i = 0; i < ClockCount; ++ i ) {
//      TightRules << "\ncircuit class " << ClassBase << i << " (use_layer  SURFACE SIG_SURF SIG_SURF2)"; // now handled in spp_clocks.do // layers on which to route clocks
      TightRules << "\nrule    class " << ClassBase << i << " (length_amplitude 100 200)";              // amplitude and gap of wiggles used to lengthen traces
      TightRules << "\nrule    class " << ClassBase << i << " (length_gap 50)";
    }
 
// assign rules to groups
    TightRules << "\n";
    for ( int i = 0; i < ClockCount; ++ i ) {
      CR_MatchClock* MC = MCV_CC[ i ];
      int Tol = MC->LongLengthMatchTolerance;   // user can override default tolerance on long length matching tolerance
      if ( Tol > 0 ) {
        TightRules << "\ncircuit group " << LongBase  << i << " (match_fromto_length on (tolerance " << Tol << "))";  // match length of long traces
      }
    }
 
    for ( int i = 0; i < MpCount; ++ i ) {
      CR_MatchClock* MC = MCV_VC[ i ];
// setting length impossibly short causes autorouter to minimize length of stubs
      TightRules << "\ncircuit group " << ShortBase << i << " (length 100)";                           // minimize length of short traces
      LooseRules << "\ncircuit group " << ShortBase << i << " (length " << MC->ShortMaxLength << ")";
    }
 
    for ( int i = 0; i < MpCount; ++ i ) {
      CR_MatchClock* MC = MCV_VC[ i ];
      TightRules << "\ncircuit group " << ShortBase << i << " (match_fromto_length on (ratio_tolerance 0.10))";
      LooseRules << "\ncircuit group " << ShortBase << i << " (match_fromto_length on (ratio_tolerance 0.20))";
    }
 
    Fromtos    << "\n";
    TightRules << "\n";
    LooseRules << "\n";
  };
 
public:
  TGenLayoutScript() {
  }
 
  void GenerateScriptFile( TRootModule* aRoot ){
// initialize member variables
    Root = aRoot;
    NL = &Root->NetList;
    PropCount = Root->Properties.GetPropertyCount();
    char*   FromtosPath    = OUTPUT_BASE "_clk_fromtos.do";
    char*   TightRulesPath = OUTPUT_BASE "_clk_tight_rules.do";
    char*   LooseRulesPath = OUTPUT_BASE "_clk_loose_rules.do";
 
    Fromtos.open( FromtosPath, ios_base::out);
    if ( !Fromtos.good() )  BEGERR << "TGenLayoutScript could not open script file " << FromtosPath << ENDERR;
    TightRules.open( TightRulesPath, ios_base::out);
    if ( !TightRules.good() )  BEGERR << "TGenLayoutScript could not open script file " << TightRulesPath << ENDERR;
    LooseRules.open( LooseRulesPath, ios_base::out);
    if ( !LooseRules.good() )  BEGERR << "TGenLayoutScript could not open script file " << LooseRulesPath << ENDERR;
 
// call functions that output to script file
    MatchClock();
 
    Fromtos.close();
    TightRules.close();
    LooseRules.close();
  }
};
 
#endif

 

Design Home <<  File View  >> Class View Output (partial) Parts Library Examples Home

Legal Copyright © 2007 by Coolquest, Inc. Contact