/* LLIBCOMP (LAY) -- Compare Layout Library Elements */ /* LLIBCOMP (LAY) -- Layout-Bibliothekselemente vergleichen */ /* // Copyright (c) 1994-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 (020620) 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 (980712) ENHANCEMENT: // Dynamic multi-language support introduced. // rl (970929) RELEASED FOR BAE V4.0. // mb (970422) CHANGE: // Adapted to new logical library features for defining // (pure) logical parts with the part command, and for // assigning attributes to physical pin lists using the // newattr command. // mb (960919) RELEASED FOR BAE V3.4. // mb (951103) IMPROVEMENT: // MNU mnu_poptext() function for compare report display used // instead of file output. // mb (951012) IMPROVEMENT: // Performing BAE_Demo_check(2) before starting output. // mb (95) RELEASED FOR BAE V3.2. // mb (950102) IMPROVEMENT: // Introduced LOGLIB alternate plname definitions evaluation. // mb (94) ORIGINAL CODING. // // DESCRIPTION // // llibcomp is a layout library management utility program // for comparing selectable layout library elements in order // to designate equivalent and/or different symbol definitions // (relating to pin naming, pin placement, padstack macro usage, // logical library element assignment, etc.). The library // comparison result report is displayed in a popup menu with // file output option. */ // Includes #include "mnu.ulh" // User Language menu utilities // Disable undo state request #pragma ULCALLERNOUNDO // Messages string UPRABORT = M_UPRABORT(); string UPRPEXIT = M_UPRPEXIT(); string REPSCANLOG = M("Scannen Loglib-Datei '%s'...", "Scanning Loglib file '%s'..."); string REPCOMP = M("Vergleichen Bauteil '%s'...", "Comparing part '%s'..."); string UPRLIB1 = M("DDB-Datei 1 ? ","DDB File 1 ? "); string UPRLIB2 = M("DDB-Datei 2 ? ","DDB File 2 ? "); string UPRPART1 = M("Bibliothek 1 Bauteil(e) ? ", "Library 1 Part(s) ? "); string UPRPART2 = M("Bibliothek 2 ('%s') Bauteil ? ", "Library 2 ('%s') Part ? "); string UPRCMACM = M("Makro-Check-Modus waehlen!", "Select Macro Check Mode!"); string UPRCMACN = M("&Kein Makro-Check","&No Macro Check"); string UPRCMACY = M("&Makro-Check","&Macro Check"); string UPRCLOGM = M("Loglib/DEF-Check/Report-Modus waehlen!", "Select Loglib/DEF Check/Report Mode!"); string UPRCLOGN = M("&Kein Loglib-Check","&No Loglib Check"); string UPRCLOGY = M("&Loglib-Check","&Loglib Check"); string UPRLIBDIR = M("Loglib/DEF-Bibliotheks-Verzeichnis : ", "Loglib/DEF Library Directory : "); string WRNMULELM = M("Mehrfach-Referenz '%s' ['%s' - '%s'] !", "Multiple reference '%s' ['%s' - '%s'] !"); string WRNPARSE = M("['%s' / %d] Parser-Fehler %d bei '%s' !", "['%s' / %d] Parser error %d at '%s' !"); string ERRNOLPRT = M("Kein Layout-Bauteil gefunden in '%s'!", "No layout part found in '%s'!"); string ERRLOAD = M("Fehler beim Laden des Bauteils '%s'!", "Error loading part '%s'!"); string ERREQUSEL = M( "Identische Bibliothekselemente fuer Vergleich selektiert!", "Identical library elements selected for comparison!"); // Output control #define FMTCMPHD "LAYOUT LIBRARY COMPARE REPORT" #define FMTCMPLIB1 " LIBRARY 1 ......: '%s'" #define FMTCMPLIB2 " LIBRARY 2 ......: '%s'" #define FMTCMPPART1 " PART 1 .........: '%s'" #define FMTCMPPART2 " PART 2 .........: '%s'" #define FMTMACCHECK " MACRO CHECK ....: %s" #define FMTLOGCHECK " LOGLIB CHECK ...: %s" #define FMTLOGLBDIR " LOGLIB DIR .....: '%s'" #define FMTPARTEXCL "PART %-*s EXCLUSIVE [%s] ;" #define FMTPARTEQU "PART %-*s EQUAL [%s EQ %s] ;" #define FMTPARTDIF "PART %-*s DIFFERENT [%s NE %s] :" #define FMTSPARTEQU "PART %s [%s] EQ %s [%s] ;" #define FMTSPARTDIF "PART %s [%s] NE %s [%s] :" #define FMTLOGELEM " LOGPART [%-*s : %c%-*s] (%s)" #define FMTPIN " PIN %*s" #define FMTPINMAC " [%-*s NE %-*s]" #define FMTPINCOORD " [%7.3f,%7.3f NE %7.3f,%7.3f]" #define FMTPINANG " (%7.3f NE %7.3f)" #define FMTPINMIR " <%d NE %d>" #define FMTPINLAY " {%d NE %d}" #define FMTVIA " VIA [%-*s %s %-*s] [%7.3f,%7.3f] (%7.3f) <%d> {%d}" #define FMTLOGUREF "UNREFERENCED PLNAME [%-*s : %c%-*s] (%s)" #define ITMYES "YES" #define ITMNO "NO" #define ITMEQ "EQ" #define ITMNE "NE" int MAXPARTLEN = 0 /* Max. part name length */; int MAXPINLEN /* Max. pin name length */; int MAXPINMACLEN /* Max. pin macro name length */; int MAXLPNLEN = 0 /* Max. logical part name length */; int MAXPLRLEN = 0 /* Max. physical lib. ref. length */; // Globals #define DEFEXT ".def" // Def file name extension #define DIRDEL "/" // Directory name delimiter string lib1 = "" /* Library 1 */; string lib2 = "" /* Library 2 */; string part1 = "" /* Part name 1 */; string part2 = "" /* Part name 2 */; string loglibdir /* Logical/DEF library directory */; STRINGS deffiles /* DEF file list */; int deffilen = 0 /* DEF file count */; int singlepart = 0 /* Single part check flag */; int macrocheck /* Macro check flag */; int loglibcheck /* Loglib/DEF check/report flag */; int curloglibidx /* Current loglib file index */; int curplrtyp /* Physical library ref. type */; string curpname /* Current part name */; STRINGS curplnamel /* Cur. physical lib. name list */; int curplnamen /* Cur. physical lib. name count */; string curstr /* Cur. string */; STRINGS msgl /* Message list */; int msgn = 0 /* Message count */; // Library masks #define LIBMASK1 0x01 #define LIBMASK2 0x02 #define LIBMASKA LIBMASK1 | LIBMASK2 // Pysical library reference types #define PLRTYPNP 0 // Normal #define PLRTYPND 1 // Normal default #define PLRTYPMP 2 // Mainpart #define PLRTYPMD 3 // Mainpart default #define PLRTYPSP 4 // Subpart #define PLRTYPVP 5 // Virtual #define PLRTYPLP 6 // Logical STRINGS plrdef = { // Physical lib. ref. designators "NP ", // Normal "ND ", // Normal default "MP ", // Mainpart "MD ", // Mainpart default "SP ", // Subpart "VP ", // Virtual "LP " // Logical }; struct logpartdes { // Logical part descriptor string pn /* Part name */; STRINGS plnl /* Physical library name list */; int plnn /* Physical library name count */; int plrtyp /* Physical library reference type */; int loglibidx /* Loglib file index */; }; struct logpartdes lps[] /* Logical part list */; int lpn = 0 /* Logical part count */; // Part list struct partdes { // Part descriptor string pn /* Part name */; int libmask /* Library mask */; } parts[] /* Part list */; int partn = 0 /* Part count */; struct { // Pin descriptor string n /* Pin name */; string mn1 /* Pin macro name 1 */; string mn2 /* Pin macro name 2 */; double x1,y1,a1 /* Pin 1 coordinates */; int m1,l1 /* Pin 1 mirror mode and layer */; double x2,y2,a2 /* Pin 2 coordinates */; int m2,l2 /* Pin 2 mirror mode and layer */; int diffpin /* Different pin flag */; int diffmac /* Different pin macros flag */; int diffcoord /* Different pin coordinates flag */; int diffangle /* Different pin angle flag */; int diffmir /* Different pin mirror flag */; int difflay /* Different pin layer flag */; } pins[] /* Pin list */; int pinn /* Pin count */; struct { // Via descriptor string mn /* Via macro name */; int exist1 /* Via 1 exist flag */; int exist2 /* Via 2 exist flag */; double x,y,a /* Via coordinates */; int m,l /* Via mirror mode and layer */; } vias[] /* Via list */; int vian /* Via count */; // Main program void main() { int jobclass /* Current element DDB class */; string jobfname /* Current element file name */; string jobename /* Current element name */; // Get current element info jobclass=bae_planddbclass(); jobfname=bae_planfname(); jobename=bae_planename(); // Save current element with verification on request verifysave(); // Select files/parts if ((lib1=askddbfile(UPRLIB1,DDBCLLPRT))=="" || (part1=asklayprt(UPRPART1,lib1))=="" || part1==UINPOPABORT || (lib2=askddbfile(UPRLIB2,DDBCLLPRT))=="" || ddbcheck(lib1,DDBCLLPRT,part1)==0 && bae_askddbename( part2,lib2,DDBCLLPRT,msgstring(UPRPART2,convstring(lib2,1)))) error_abort(); // Set second part name if (part2=="") part2=part1; else singlepart=1; // Check on identical part selection if (lib1==lib2 && part1==part2) error(ERREQUSEL); // Get macro check mode bae_promptdialog(UPRCMACM); if ((macrocheck=bae_askmenu(3,UPRCMACN,UPRCMACY,UPRABORT))>1 || macrocheck<0) error_abort(); // Get loglib/DEF check/report mode bae_promptdialog(UPRCLOGM); switch (loglibcheck=bae_askmenu(3,UPRCLOGN,UPRCLOGY,UPRABORT)) { case 0 : break; case 1 : // Ask for library directory name if ((loglibdir=askstr(UPRLIBDIR,MAXKEYLEN))!="") { // Check if abort request if (loglibdir==UINPOPABORT) error_abort(); // Build the library file lists buildfilelist(loglibdir); // Scan the logical library scanloglib(); } break; default : error_abort(); } // Issue compare list header msgl[msgn++]=FMTCMPHD; msgl[msgn++]=""; sprintf(msgl[msgn],FMTCMPLIB1,lib1); msgn++; sprintf(msgl[msgn],FMTCMPLIB2,lib2); msgn++; sprintf(msgl[msgn],FMTCMPPART1,part1); msgn++; sprintf(msgl[msgn],FMTCMPPART2,part2); msgn++; sprintf(msgl[msgn],FMTMACCHECK,macrocheck ? ITMYES : ITMNO); msgn++; sprintf(msgl[msgn],FMTLOGCHECK,loglibcheck ? ITMYES : ITMNO); msgn++; if (loglibcheck) { sprintf(msgl[msgn],FMTLOGLBDIR,loglibdir); msgn++; } msgl[msgn++]=""; // Compare selected parts if (singlepart) // Single part comparison cmpparts(lib1,lib2,part1,part2); else // Multiple part comparison scanparts(); // Reload the original element if (jobclass!=DDBCLUNDEF && (jobclass!=bae_planddbclass() || jobfname!=bae_planfname() || jobename!=bae_planename())) { bae_setintpar(22,2); bae_loadelem(jobfname,jobename,jobclass); } // Display library comparison report with popup menu bae_setintpar(16,4019); mnu_poptext(msgl,1,1,-1,0,0); } string asklayprt(string prompt,string filename) /* // Perform a layout part selection via popup menu // Return value : // name of selected element or empty string on abort // Parameters : // string prompt : Prompt string // string filename : File name */ { STRINGS headl /* Header string list */; int headn = 2 /* Header string count */; STRINGS entryl /* Entry string list */; int entryn = 0 /* Entry list */; string project = UINPOPABORT /* Project name */; string ename /* Current element name */; // Abort on DDB file access failure if (ddbcheck(filename,DDBCLLPRT,"")) errormsg(ERRNOLPRT,filename); // Define the header headl[0]=M_REPPOPDIRHD(DDBCLLPRT,filename); headl[headn-1]=""; // Set the project name if (bae_planfname()==filename && bae_planddbclass()==DDBCLLPRT) project=bae_planename(); // Scan the element name list message(M_REPSCANDDB(),filename); ename=""; while (scanddbenames(filename,DDBCLLPRT,ename)==1) // Append the element name to the menu entryl[entryn++]=ename; // Activate the popup and return the element name bae_setintpar(16,4033); return(popupmenu(1,prompt, headl,headn,entryl,entryn,project,0,0,1,0,0,0,"")); } void buildfilelist(string dname) /* // Build file list // Parameters : // string dname : Directory name */ { // Get the def file list filelist(deffiles,deffilen,dname,DEFEXT,"",0,0,1,0,1,0); } void scanloglib() /* // Build the LOG library contents file // Return value : // zero if done or (-1) on error */ { int sts /* Status code */; // Init the logical part count lpn=0; // Loop thru the def file list synscaneoln(0); for (curloglibidx=0;curloglibidx>1; // Get and test the compare result if ((compres=numstrcmp(pn,lps[idx].pn))==0) { sprintf(msgl[msgn],WRNMULELM, pn,deffiles[curloglibidx], deffiles[lps[idx].loglibidx]); msgn++; return; } // Update the search area if (compres<0) sub=idx-1; else slb=idx+1; } // Insert the new entry to the logical part list lpn++; for (idx=lpn-2;idx>=slb;idx--) lps[idx+1]=lps[idx]; lps[slb].loglibidx=curloglibidx; lps[slb].pn=pn; for (idx=plnn-1;idx>=0;idx--) lps[slb].plnl[idx]=plnl[idx]; lps[slb].plnn=plnn; lps[slb].plrtyp=plrtyp; MAXLPNLEN=maxint(MAXLPNLEN,strlen(pn)); MAXPLRLEN=maxint(MAXPLRLEN,strlen(plrdef[plrtyp])); } void createpart(string pn,int libmask) /* // Create a part list entry // Parameters : // string pn : Part name // int libmask : Library mask */ { int idx /* Search index */; int insidx = (-1) /* Insert index */; // Loop until search area empty if ((idx=findpart(pn,insidx))>=0) { // Part found; set library mask parts[idx].libmask |= libmask; // Done return; } // Insert the new entry to the part list partn++; for (idx=partn-2;idx>=insidx;idx--) parts[idx+1]=parts[idx]; parts[insidx].libmask=libmask; parts[insidx].pn=pn; MAXPARTLEN=maxint(MAXPARTLEN,strlen(pn)); } int findpart(string pn,int insidx=(-1)) /* // Find a part list entry // Return value : // part list index or (-1) if not found // Parameters : // string pn : Part name // int insidx = (-1) : Insert index */ { int slb = 0 /* Search lower boundary */; int sub = partn-1 /* Search upper boundary */; int idx /* Search index */; int compres /* Compare result */; // Loop until search area empty while (slb<=sub) { // Get the search index idx=(slb+sub)>>1; // Get and test the compare result if ((compres=numstrcmp(pn,parts[idx].pn))==0) return(idx); // Update the search area if (compres<0) sub=idx-1; else slb=idx+1; } // Part not found insidx=slb; return(-1); } void gcpin1(string pn,string pmn, double x,double y,double a,int m,int l) /* // Get or create some pin entry // Parameters : // string pn : Pin name // string pmn : Pin macro name // double x : Pin X coordinate // double y : Pin Y coordinate // double a : Pin rotation angle // int m : Pin mirror mode // int l : Pin mirror layer */ { int slb = 0 /* Search lower boundary */; int sub = pinn-1 /* Search upper boundary */; int idx /* Search index */; int compres /* Compare result */; // Loop until search area empty while (slb<=sub) { // Get the search index idx=(slb+sub)>>1; // Get and test the compare result if ((compres=numstrcmp(pn,pins[idx].n))==0) return; // Update the search area if (compres<0) sub=idx-1; else slb=idx+1; } // Insert the new entry to the logical part list pinn++; for (idx=pinn-2;idx>=slb;idx--) pins[idx+1]=pins[idx]; pins[slb].n=pn; pins[slb].mn1=pmn; pins[slb].x1=x; pins[slb].y1=y; pins[slb].a1=a; pins[slb].m1=m; pins[slb].l1=l; pins[slb].mn2=""; pins[slb].x2=0.0; pins[slb].y2=0.0; pins[slb].a2=0.0; pins[slb].m2=0; pins[slb].l2=0; MAXPINLEN=maxint(MAXPINLEN,strlen(pn)); MAXPINMACLEN=maxint(MAXPINMACLEN,strlen(pmn)); } void gcpin2(string pn,string pmn, double x,double y,double a,int m,int l) /* // Get or create some pin entry // Parameters : // string pn : Pin name // string pmn : Pin macro name // double x : Pin X coordinate // double y : Pin Y coordinate // double a : Pin rotation angle // int m : Pin mirror mode // int l : Pin layer offset */ { int slb = 0 /* Search lower boundary */; int sub = pinn-1 /* Search upper boundary */; int idx /* Search index */; int compres /* Compare result */; // Loop until search area empty while (slb<=sub) { // Get the search index idx=(slb+sub)>>1; // Get and test the compare result if ((compres=numstrcmp(pn,pins[idx].n))==0) { pins[idx].n=pn; pins[idx].mn2=pmn; pins[idx].x2=x; pins[idx].y2=y; pins[idx].a2=a; pins[idx].m2=m; pins[slb].l2=l; return; } // Update the search area if (compres<0) sub=idx-1; else slb=idx+1; } // Insert the new entry to the logical part list pinn++; for (idx=pinn-2;idx>=slb;idx--) pins[idx+1]=pins[idx]; pins[slb].n=pn; pins[slb].mn2=pmn; pins[slb].x2=x; pins[slb].y2=y; pins[slb].a2=a; pins[slb].m2=m; pins[slb].l2=l; pins[slb].mn1=""; pins[slb].x1=0.0; pins[slb].y1=0.0; pins[slb].a1=0.0; pins[slb].m1=0; pins[slb].l1=0; MAXPINLEN=maxint(MAXPINLEN,strlen(pn)); MAXPINMACLEN=maxint(MAXPINMACLEN,strlen(pmn)); } void gcvia1(string pmn, double x,double y,double a,int m,int l) /* // Get or create some via entry // Parameters : // string pmn : Via macro name // double x : Via X coordinate // double y : Via Y coordinate // double a : Via rotation angle // int m : Via mirror mode // int l : Via layer */ { int slb = 0 /* Search lower boundary */; int sub = vian-1 /* Search upper boundary */; int idx /* Search index */; int compres /* Compare result */; // Loop until search area empty while (slb<=sub) { // Get the search index idx=(slb+sub)>>1; // Get and test the compare result if ((compres=numstrcmp(pmn,vias[idx].mn))==0 && (compres=cmpdbl(x,vias[idx].x))==0 && (compres=cmpdbl(y,vias[idx].y))==0 && (compres=cmpdbl(a,vias[idx].a))==0 && (compres=a-vias[idx].m)==0 && (compres=l-vias[idx].l)==0) return; // Update the search area if (compres<0) sub=idx-1; else slb=idx+1; } // Insert the new entry to the logical part list vian++; for (idx=vian-2;idx>=slb;idx--) vias[idx+1]=vias[idx]; vias[slb].mn=pmn; vias[slb].exist1=1; vias[slb].x=x; vias[slb].y=y; vias[slb].a=a; vias[slb].m=m; vias[slb].l=l; vias[slb].exist2=0; MAXPINMACLEN=maxint(MAXPINMACLEN,strlen(pmn)); } void gcvia2(string pmn, double x,double y,double a,int m,int l) /* // Get or create some pin entry // Parameters : // string pmn : Via macro name // double x : Via X coordinate // double y : Via Y coordinate // double a : Via rotation angle // int m : Via mirror mode // int l : Via layer offset */ { int slb = 0 /* Search lower boundary */; int sub = vian-1 /* Search upper boundary */; int idx /* Search index */; int compres /* Compare result */; // Loop until search area empty while (slb<=sub) { // Get the search index idx=(slb+sub)>>1; // Get and test the compare result if ((compres=numstrcmp(pmn,vias[idx].mn))==0 && (compres=cmpdbl(x,vias[idx].x))==0 && (compres=cmpdbl(y,vias[idx].y))==0 && (compres=cmpdbl(a,vias[idx].a))==0 && (compres=a-vias[idx].m)==0 && (compres=l-vias[idx].l)==0) { vias[idx].exist2=1; return; } // Update the search area if (compres<0) sub=idx-1; else slb=idx+1; } // Insert the new entry to the logical part list vian++; for (idx=vian-2;idx>=slb;idx--) vias[idx+1]=vias[idx]; vias[slb].mn=pmn; vias[slb].exist2=1; vias[slb].exist1=0; vias[slb].x=x; vias[slb].y=y; vias[slb].a=a; vias[slb].m=m; vias[slb].l=l; MAXPINMACLEN=maxint(MAXPINMACLEN,strlen(pmn)); } /*________________________________________________________________*/ // Data conversion routines int cmpdbl(double v1,double v2) /* // Compare two double values // Return value : // 0 if v1==v2, -1 if v1v2) // Parameters : // double v1 : Input double value 1 // double v2 : Input double value 2 */ { // Test if equal if (v1==v2) // Return equal result return(0); // Return non-equal result return(v1