/* ROUTINFO (LAY) -- Routing Data Analysis */ /* ROUTINFO (LAY) -- Routingdatenanalyse */ /* // Copyright (c) 1998-2012 Oliver Bartels F+E, Muenchen // Author: Manfred Baumeister // Changes History: // rl (120427) RELEASED FOR BAE V7.8. // rl (101019) RELEASED FOR BAE V7.6. // rl (091021) RELEASED FOR BAE V7.4. // rl (081014) RELEASED FOR BAE V7.2. // rl (071029) RELEASED FOR BAE V7.0. // rl (060829) RELEASED FOR BAE V6.8. // rl (050906) RELEASED FOR BAE V6.6. // rl (040811) RELEASED FOR BAE V6.4. // rl (030904) RELEASED FOR BAE V6.2. // rl (021209) RELEASED FOR BAE V6.0. // rl (020618) RELEASED FOR BAE V5.4. // rl (010625) RELEASED FOR BAE V5.0. // rl (000509) RELEASED FOR BAE V4.6. // rl (990625) RELEASED FOR BAE V4.4. // rl (980910) RELEASED FOR BAE V4.2. // mb (980711) ENHANCEMENT: // Dynamic multi-language support introduced. // rl (970929) RELEASED FOR BAE V4.0. // ob (970705) CHANGE: // Added $netlen net attribute backannotation support. // mb (970515) ORIGINAL CODING. // // DESCRIPTION // // The routinfo User Language program creates comprehensive layout // trace length analysis reports to be stored with the currently // processed layout and/or checked against previous results in // order to estimate multiple router pass performance or consider // re-entrant routing results after redesign. */ // Includes #include "pop.ulh" // User Language popup utilities #include "sql.ulh" // User Language SQL utilities #include "lay.ulh" // User Language layout utilities // Disable undo state request #pragma ULCALLERNOUNDO // Messages string UPRABORT = M_UPRABORT(); string UPRSORTMODE = M("Anzeigesortierung selektieren!", "Select Display Sort Mode!"); string REPSCANNET = M("Scannen Netze...","Scanning Nets..."); string REPSCANTRC = M("Scannen Leiterbahnen...","Scanning Traces..."); string REPFMTNETS = M("Formatieren Netzliste...", "Formatting Net List..."); string REPSORTNETS = M("Sortieren Netliste...","Sorting Net List..."); string UPRCRERTAB = M("Rout-Info-Tabelle aktualisieren ? ", "Update Rout Info Table ? "); string FMTHEAD1 = M("Layout Routing-Datenreport", "Routing Data Report"); string FMTHEAD2 = M(" DDB-Dateiname .........: '%s'", " DDB File Name .........: '%s'"); string FMTHEAD3 = M(" Layout-Elementname ....: '%s'", " Layout Element Name ...: '%s'"); string FMTHEAD4 = M(" Anzahl Netze ..........: %d (%d geaendert)", " Net Count .............: %d (%d changed)"); string FMTHEAD5 = M(" Netze sortiert nach ...: %s", " Nets sorted by ........: %s"); string ITMNETNAME = M("Netzname","Net Name"); string FMTLISTHD1 = M("Leiterbahnlaengen %s","Trace Lengths %s"); string FMTLISTHD2 = M(" Aktuell Vorher Aenderung ", " Current Previous Change ")+ITMNETNAME; string ITMALLNET = M("=Gesamt=","=Total="); string ERRDBINIT = M("SQL/DB-Datei '%s' kann nicht initialisiert werden!", "Error initialyzing SQL/DB file '%s'!"); STRINGS ITMSORTMODES = { M("Netzname","Net Name"), M("Bahnlaenge aktuell","Trace Length &Cur."), M("Bahnlaenge vorher","Trace Length &Prev."), M("Laengenaenderung","Trace Len. Change") }; // General item and format strings #define ITMULINE "========================================" #define FMTLISTUL "========== ========== ========== %.*s" #define FMTNET "%10.3f %10.3f %10.3f %s" #define ITMUNITMM "[mm]" #define ITMUNITINCH "[Inch]" string ITMUNIT = bae_getcoorddisp() ? ITMUNITINCH : ITMUNITMM /* Display units designator */; // Globals #define SMALLLEN 0.0000005 // Small length value int MAXNETNAMLEN = strlen(ITMNETNAME) /* Max. net name lenth */; #define NETLENATTR "$netlen" // Net length attribute name #define SORTNONE (-1) // None/invalid sort mode #define SORTNAME 0 // Sort by net name #define SORTCLEN 1 // Sort by current rout length #define SORTPLEN 2 // Sort by previous rout length #define SORTLCHG 3 // Sort by rout length change typedef struct { // Net entry descriptor index L_CNET net /* Net name */; double curlen /* Current net trace length */; double prvlen /* Previous net trace length */; string popentry /* Popup menu entry */; } NETENTRY /* Net entry type definition */; NETENTRY netl[] /* Net entry list */; int netn /* Net count */; double rlencur = 0.0 /* Total current rout length */; double rlenprv = 0.0 /* Total previous rout length */; int rchgcnt = 0 /* Rout length change count */; int sortmode = SORTNONE /* Net list sort mode */; int sortl[] /* Sorted net list indices */; // SQL database access definitions string R_TABFILE = bae_planfname(); string R_TABNAME = bae_planename()+"_routinfo"; #define CRES "create table " #define CREE " (netname string,trclen float);" #define INSS "insert into " #define INSE " values('%s',%f);" #define SELS "select trclen from " #define SELE " where netname='%s';" #define DRPS "drop table " #define DRPE ";" string R_CREATE = CRES+R_TABNAME+CREE; string R_INSERT = INSS+R_TABNAME+INSE; string R_SELECT = SELS+R_TABNAME+SELE; string R_DROP = DRPS+R_TABNAME+DRPE; double curtrclen /* Current trace length value */; // Main program void main() { int newsortmode /* New net list sort mode */; // Abort if invalid plan class if (bae_planddbclass()!=DDBCLLAY) error_class(); // Create/init the SQL database if (sqlinit(R_TABFILE,1)==(-1)) // SQL/DB create/init error errormsg(ERRDBINIT,R_TABFILE); // Build the net list buildnetlist(); // Store the trace length info tracelist(); // Update all net attributes updnetattr(); // Format the netlist entries for popup menu display rchgcnt=formatnetlist(); // Provide net list display with sort options while ((newsortmode=asksortmode())!=SORTNONE) { // Sort the net list on request if (newsortmode!=sortmode) { sortmode=newsortmode; sortnetlist(sortmode); } // Display the routing data info disproutinfo(); } // Store the routing data info on request if (rchgcnt && verify(UPRCRERTAB,0)) createroutinfotab(); // Done bae_prtdialog(""); } int asksortmode() /* // Ask user for net list sort mode // Return value : // selected sort mode */ { // Perform sort mode query bae_promptdialog(UPRSORTMODE); switch (bae_askmenu(5,ITMSORTMODES[0],ITMSORTMODES[1], ITMSORTMODES[2],ITMSORTMODES[3],UPRABORT)) { case 0 : return(SORTNAME); case 1 : return(SORTCLEN); case 2 : return(SORTPLEN); case 3 : return(SORTLCHG); case 4 : return(SORTNONE); default : error_abort(); } // Return invalid sort mode return(SORTNONE); } void disproutinfo() /* // Display the routing data info */ { STRINGS hl /* Popup menu header list */; STRINGS el /* Popup menu entry list */; int hn /* Popup menu header count */; int i /* Loop control variable */; // Set the popup menu entries for (i=netn-1;i>=0;i--) el[i]=netl[sortl[i]].popentry; // Build the popup menu contents hl[0]=FMTHEAD1; hl[1]=" "; sprintf(hl[2],FMTHEAD2,bae_planfname()); sprintf(hl[3],FMTHEAD3,bae_planename()); sprintf(hl[4],FMTHEAD4,netn,rchgcnt); sprintf(hl[5],FMTHEAD5,ITMSORTMODES[sortmode]); hl[6]=" "; sprintf(hl[7],FMTLISTHD1,ITMUNIT); sprintf(hl[8],FMTLISTHD2); sprintf(hl[9],FMTLISTUL,MAXNETNAMLEN,ITMULINE); sprintf(hl[10],FMTNET, baecvtl(rlencur),baecvtl(rlenprv), baecvtl(rlencur-rlenprv),ITMALLNET); sprintf(hl[11],FMTLISTUL,MAXNETNAMLEN,ITMULINE); hn=12; // Activate the popup menu bae_setintpar(16,4036); if (popupmenu(0,"",hl,hn,el,netn,UINPOPABORT,0,0,1, hn+netn+2,0,0,"")==UINPOPABORT) error_abort(); } /*________________________________________________________________*/ // SQL database management routines void createroutinfotab() /* // Create/update the net rout info table */ { string sqlcmd /* SQL command string buffer */; int i /* Loop control variable */; // Assume database file is already initialyzed for write // Drop existing table if (sqlcmd(R_TABFILE,R_DROP,NULL)) // SQL/DB error (ignore table not found error) sql_dberror(27); // Create SQL database table if (sqlcmd(R_TABFILE,R_CREATE,NULL)) // SQL/DB error (ignore table already defined error) sql_dberror(25); // Insert all table entries for (i=0;i=0) // Assume internal error on multiple nets names err_intern("buildnetlist"); // Insert new net to netlist for (i=netn;i>insidx;i--) netl[i]=netl[i-1]; // Get previous net trace length (ignore errors) curtrclen=0.0; sprintf(sqlcommand,R_SELECT,cnet.NAME); sqlcmd(R_TABFILE,sqlcommand,trclenselfunc); // Store net list entry netl[insidx].prvlen=curtrclen; netl[insidx].curlen=0; netl[insidx].net=cnet; netn++; // Update the maximum net name length MAXNETNAMLEN=maxint(MAXNETNAMLEN,strlen(cnet.NAME)); } } void tracelist() /* // Store the trace information to the net list */ { index L_LINE l /* Line (=TRACE) index */; index L_POINT p /* Point index (of line) */; int pc /* Point counter */; int t1 /* Previous point type */; double x1,y1 /* Previous point coordinate */; int t2 /* Pre-previous point type */; double x2,y2 /* Pre-previous point coordinate */; double tl /* Trace length */; int sc /* Segment count */; int idx /* Index buffer */; // Issue report message bae_prtdialog(REPSCANTRC); // Loop thru the line list forall (l) { // Get net list index if ((idx=findnet(treenetname(l.TREE),-1))<0) // Ignore unnamed net continue; // Init the trace point and segment counters pc=sc=0; // Init the trace length tl=0.0; // Loop thru the trace point list forall (p of l) { // Increment the point counter pc++; // Get segment length and update trace length tl+=segmentlen( pc,p.TYP,p.X,p.Y,t1,x1,y1,t2,x2,y2,sc); } // Update the net-specific routing length netl[idx].curlen+=tl; // Update the global routing length rlencur+=tl; } } void updnetattr() /* // Update all net list trace length attributes */ { string lenvalstr /* Length value string */; int i /* Loop control variable */; // Loop for all nets for (i=0;i=0;i--) sortl[i]=i; // Done return; } /* Loop thru the net list */ for (i=0;i>1; // Get the net entry ns=netl[sortl[sidx]]; // Evaluate the sort mode switch (sortmode) { // Sort by current rout length case SORTCLEN : compres=cmpdbl(ns.curlen,n.curlen); break; // Sort by previous rout length case SORTPLEN : compres=cmpdbl(ns.prvlen,n.prvlen); break; // Sort by rout length change case SORTLCHG : compres=cmpdbl( ns.curlen-ns.prvlen,n.curlen-n.prvlen); break; // Assume internal error on default default : err_intern("sortnetlist"); } // Perform additional net name sort if (compres==0 && (compres=numstrcmp(n.net.NAME,ns.net.NAME))==0) // Assume internal error err_intern("sortnetlist"); // Update the search area if (compres<0) sub=sidx-1; else slb=sidx+1; } // Insert sorted net list entry to list for (sidx=sortn;sidx>slb;sidx--) sortl[sidx]=sortl[sidx-1]; sortl[slb]=i; sortn++; } } int findnet(string netname,int insidx=(-1)) /* // Store net to net list // Parameters : // string netname : Net name // int insidx : insert index */ { int slb = 0 /* Search lower boundary */; int sub = netn-1 /* Search upper boundary */; int sidx /* Search index */; int compres /* Compare result */; // Loop until search area empty while (slb<=sub) { // Get the search index sidx=(slb+sub)>>1; // Test if net found if ((compres=numstrcmp(netname,netl[sidx].net.NAME))==0) // Net found return(sidx); // Update the search area if (compres<0) sub=sidx-1; else slb=sidx+1; } // Net not found insidx=slb; return(-1); } string treenetname(int treenum) /* // Get net name for given tree number // Return value : // net name or empty string if no valid net // Parameters : // int treenum : Tree number */ { index L_CNET cnet /* Connection net index */; // Get and return tree net name return(lay_gettreeidx(treenum,cnet)==0 ? cnet.NAME : ""); } /*________________________________________________________________*/ // Utility routines int cmpdbl(double v1,double v2) /* // Compare double values // Return value : // zero if equal, (-1) if v1