// chipdatabase.cpp #include <math.h> #include <stdarg.h> #include <time.h> #include "ps.h" #include "color.h" #include "chipdatabase.h" void CLogFile::Init() { logTime[0] = 0; logVersion[0] = 0; productId[0] = 0; waferId[0] = 0; waferNr[0] = 0; } bool CLogFile::open(char logFileName[]) { Init(); if (!Log.open(logFileName)) ERROR_ABORT(ERROR_OPEN) if (!readHeader()) return false; return true; } // logDate "Apr 17 13:53:45 2006" // xmlDate "04-17-2006 13:53:45" const char CChip::monthNames[12][4] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dec" }; bool CChip::ConvertDate(char *xmlDate) { char monstr[4]; int year, month, day, h, m, s; if (sscanf(startTime, "%3s %d %d:%d:%d %d", monstr, &day, &h, &m, &s, &year) != 6) return false; month = 0; while (month<12 && strcmp(monthNames[month],monstr)!=0) month++; month++; if (month>12) return false; if (day<1 || 31<day) return false; if (year<1900 || 2500<year) return false; if (h<0 || 23<h) return false; if (m<0 || 59<m) return false; if (s<0 || 59<m) return false; sprintf(xmlDate, "%04i-%02i-%02i %02i:%02i:%02i", year, month, day, h, m, s); return true; } bool CLogFile::rewind() { if (!Log.rewind()) ERROR_ABORT(ERROR_OPEN) if (!readHeader()) return false; return true; } bool CLogFile::readHeader() { // read [OPEN] section if (!Log.isSection("OPEN")) ERROR_ABORT(ERROR_NO_LOGFILE) Log.getNextLine(); if (strlen(Log.getLine())<12) ERROR_ABORT(ERROR_NO_LOGFILE) strncpy(logTime,Log.getNextLine()+5,24); // read [VERSION] section if (!Log.getNextSection("VERSION")) ERROR_ABORT(ERROR_NO_LOGFILE) Log.getNextLine(); if (strlen(Log.getLine())<3) ERROR_ABORT(ERROR_NO_LOGFILE) strncpy(logVersion,Log.getNextLine(),43); Log.getNextSection(); if (Log.isSection("CPU")) { Log.getNextSection(); } if (Log.isSection("ATB")) { Log.getNextSection(); } return true; } bool CLogFile::readChip(CChip &chip) { // read [WAFER] section if exist if (Log.isSection("WAFER")) { if (sscanf(Log.getNextLine(),"%39s%39s%9s", productId,waferId,waferNr) != 3) ERROR_ABORT(ERROR_WAFERID) Log.getNextSection(); } chip.Invalidate(); strcpy(chip.productId, productId); strcpy(chip.waferId, waferId); strcpy(chip.waferNr, waferNr); return chip.Read(Log); } bool CLogFile::checkFileEnd() { return Log.isSection("CLOSE"); // if (!Log.isSection("CLOSE")) ERROR_ABORT(ERROR_CLOSE) // return true; } bool CAnalogLevel::Read(CScanner &Log) { if (sscanf(Log.getNextLine(), "%i %lf %lf %i %i", &n, &mean, &stdev, &min, &max) != 5) return false; exist = true; return true; } void CAnalogLevel::Save(const char name[], FILE *f) { fprintf(f,"%s: exist=%s", name, exist?"true ":"false\n"); if (exist) fprintf(f,"n=%i mean=%0.1f stdev=%0.1f min=%i max=%i\n", n, mean, stdev, min, max); } void CChip::Invalidate() { int i; multi = 0; nEntry = 0; productId[0]=waferId[0]=waferNr[0]=chipId[0]=0; mapX = mapY = mapPos = 0; startTime[0] = endTime[0] = 0; frequency = -1; IdigOn = IanaOn = IdigInit = IanaInit = -1.0; probecard.Init(); for (i=0; i<5; i++) Iana[i] = -1.0; InitVana = -1; InitIana = -1.0; ublack.Init(); black.Init(); for (i=0; i<6; i++) l[i].Init(); token = -1; i2c = -1; bin = -1; pixtest2 = 0; logChipClass = -1; chipClass = 5; pickClass = 5; pickGroup = 99; nPh = 0; nPhFail = 0; pixmap.Init(); dcol.Init(); } void CChip::getCurrent(CScanner &Log, double *Idig, double *Iana) { if (Log.getLine()[0] == 0) return; char s[8]; double i; if (sscanf(Log.getLine(),"%5s %lf", s, &i)==2) { if (strcmp("Iana=",s)==0) *Iana = i; else *Idig = i; } Log.getNextLine(); } void CChip::Save(FILE *f) { fprintf(f,"nEntry: %i\n", nEntry); fprintf(f,"productId: %s\n", productId); fprintf(f,"waferId: %s\n", waferId); fprintf(f,"waferNr: %s\n", waferNr); fprintf(f,"mapX: %i\n", mapX); fprintf(f,"mapY: %i\n", mapY); fprintf(f,"mapPos: %i\n", mapPos); fprintf(f,"chipId: %s\n", chipId); fprintf(f,"startTime: %s", startTime); fprintf(f,"endTime: %s", endTime); fprintf(f,"frequency: %i\n", frequency); fprintf(f,"IdigOn: %0.1f mA\n", IdigOn); fprintf(f,"IanaOn: %0.1f mA\n", IanaOn); fprintf(f,"IdigInit: %0.1f mA\n", IdigInit); fprintf(f,"IanaInit: %0.1f mA\n", IanaInit); fprintf(f,"probecard.isValid: %s\n", probecard.isValid?"true":"false"); if (probecard.isValid) { fprintf(f,"probecard.v_aout: %0.3f V\n", probecard.v_aout); fprintf(f,"probecard.v_dac: %0.3f V\n", probecard.v_dac); fprintf(f,"probecard.v_tout: %0.3f V\n", probecard.v_tout); fprintf(f,"probecard.vd_cap: %0.3f V\n", probecard.vd_cap); fprintf(f,"probecard.vd_reg: %0.3f V\n", probecard.vd_reg); } fprintf(f,"Iana: %0.1f %0.1f %0.1f %0.1f %0.1f\n", Iana[0],Iana[1],Iana[2],Iana[3],Iana[4]); fprintf(f,"InitVana: %i\n", InitVana); fprintf(f,"InitIana: %0.1f mA\n", InitIana); ublack.Save("ublack", f); black.Save("black", f); l[0].Save("l[0]", f); l[1].Save("l[1]", f); l[2].Save("l[2]", f); l[3].Save("l[3]", f); l[4].Save("l[4]", f); l[5].Save("l[5]", f); fprintf(f,"token: %i\n", token); fprintf(f,"i2c: %i\n", i2c); fprintf(f,"bin: %i\n", bin); // pixmap.Save(f); // dcol.Save(f); } bool CChip::Read(CScanner &Log) { // read [CHIP] section if (Log.isSection("CHIP")) // chip on wafer { char ch; if (sscanf(Log.getNextLine(),"%i%i %c",&mapX, &mapY, &ch)!=3) ERROR_ABORT(ERROR_CHIP); if ('A'<=ch && ch<='D') mapPos = ch - 'A'; else ERROR_ABORT(ERROR_CHIP); sprintf(chipId, "%i%i%c", mapY, mapX, ch); } else if (Log.isSection("CHIP1")) // single chip { if (sscanf(Log.getNextLine(),"%40s",chipId) != 1) ERROR_ABORT(ERROR_CHIP); mapX = mapY = mapPos = 0; } else ERROR_ABORT(ERROR_OK) Log.getNextSection(); // read [BEGIN] section if (!Log.isSection("BEGIN")) ERROR_ABORT(ERROR_BEGIN) Log.getNextLine(); if (strlen(Log.getLine())<12) ERROR_ABORT(ERROR_BEGIN) strncpy(startTime,Log.getNextLine()+5,24); Log.getNextSection(); // read FREQ section if exist if (Log.isSection("FREQ")) { if (sscanf(Log.getNextLine(), "%i", &frequency)!=1) ERROR_ABORT(ERROR_FREQ) Log.getNextSection(); } // read [PON] section if (!Log.isSection("PON")) ERROR_ABORT(ERROR_PON) if (sscanf(Log.getNextLine(),"%i", &nEntry)!=1) ERROR_ABORT(ERROR_PON) Log.getNextLine(); getCurrent(Log,&IdigOn,&IanaOn); getCurrent(Log,&IdigOn,&IanaOn); Log.getNextSection(); // read [INIT] section if exist if (Log.isSection("INIT")) { Log.getNextLine(); Log.getNextLine(); getCurrent(Log,&IdigInit,&IanaInit); getCurrent(Log,&IdigInit,&IanaInit); Log.getNextSection(); } // read [VDCAP] if exist if (Log.isSection("VDCAP")) { if (sscanf(Log.getNextLine(), "%lf", &probecard.vd_cap)!=1) ERROR_ABORT(ERROR_PROBECARD) if (!Log.getNextSection("VDREG","TOKEN")) ERROR_ABORT(ERROR_PROBECARD); if (sscanf(Log.getNextLine(), "%lf", &probecard.vd_reg)!=1) ERROR_ABORT(ERROR_PROBECARD); if (!Log.getNextSection("VDAC","TOKEN")) ERROR_ABORT(ERROR_PROBECARD); if (sscanf(Log.getNextLine(), "%lf", &probecard.v_dac)!=1) ERROR_ABORT(ERROR_PROBECARD); if (!Log.getNextSection("VTOUT","TOKEN")) ERROR_ABORT(ERROR_PROBECARD); if (sscanf(Log.getNextLine(), "%lf", &probecard.v_tout)!=1) ERROR_ABORT(ERROR_PROBECARD); if (!Log.getNextSection("VAOUT","TOKEN")) ERROR_ABORT(ERROR_PROBECARD); if (sscanf(Log.getNextLine(), "%lf", &probecard.v_aout)!=1) ERROR_ABORT(ERROR_PROBECARD); probecard.isValid = true; Log.getNextSection(); } // read [TOKEN] section if exist if (Log.isSection("TOKEN")) { if (sscanf(Log.getNextLine(),"%i", &token)!=1) ERROR_ABORT(ERROR_TOKEN) Log.getNextSection(); } // read [I2C] section if exist if (Log.isSection("I2C")) { Log.getNextLine(); i2c = (strlen(Log.getNextLine()) == 0) ? 1 : 0; Log.getNextSection(); } // read [VANA] section if exist if (Log.isSection("VANA")) { int dac; Log.getNextLine(); if (sscanf(Log.getNextLine(),"%i %lf",&dac,&Iana[0])!=2) ERROR_ABORT(ERROR_VANA) if (dac!=64) ERROR_ABORT(ERROR_VANA) if (sscanf(Log.getNextLine(),"%i %lf",&dac,&Iana[1])!=2) ERROR_ABORT(ERROR_VANA) if (dac!=96) ERROR_ABORT(ERROR_VANA) if (sscanf(Log.getNextLine(),"%i %lf",&dac,&Iana[2])!=2) ERROR_ABORT(ERROR_VANA) if (dac!=128) ERROR_ABORT(ERROR_VANA) if (sscanf(Log.getNextLine(),"%i %lf",&dac,&Iana[3])!=2) ERROR_ABORT(ERROR_VANA) if (dac!=160) ERROR_ABORT(ERROR_VANA) if (sscanf(Log.getNextLine(),"%i %lf",&dac,&Iana[4])!=2) ERROR_ABORT(ERROR_VANA) if (dac!=192) ERROR_ABORT(ERROR_VANA) Log.getNextSection(); } // skip [IANA] sections while (Log.isSection("IANA")) Log.getNextSection(); // read [ITRIM] section if exist if (Log.isSection("ITRIM")) { if (sscanf(Log.getNextLine(),"%i %lf", &InitVana, &InitIana)!=2) ERROR_ABORT(ERROR_ITRIM) Log.getNextSection(); } if (Log.isSection("TEMP")) Log.getNextSection(); if (Log.isSection("DAC")) Log.getNextSection(); if (Log.isSection("LVLDET")) Log.getNextSection(); if (Log.isSection("AOUTHIST")) Log.getNextSection(); if (Log.isSection("PIXEL")) Log.getNextSection(); // read [AOUT] section if (Log.isSection("AOUT")) { Log.getNextLine(); if (!black.Read(Log)) ERROR_ABORT(ERROR_AOUT) if (!ublack.Read(Log)) ERROR_ABORT(ERROR_AOUT) for (int i=0; i<6; i++) if (!l[i].Read(Log)) ERROR_ABORT(ERROR_AOUT) Log.getNextSection(); } while (Log.isSection("PIXTEST2")) { char *s = Log.getNextLine(); char *pos = strchr(s,')'); if (pos) { if (pos[1] == 'd') pixtest2 += 256; else if (pos[1] == 'w') pixtest2 += 1; } Log.getNextSection(); } if (Log.isSection("DELSCAN")) Log.getNextSection(); // read [DCOL] section if exist if (Log.isSection("DCOL")) { Log.getNextLine(); if (!dcol.read(Log)) ERROR_ABORT(ERROR_DCOL) Log.getNextSection(); } // read [PIXMAP] section if exist if (Log.isSection("PIXMAP")) { Log.getNextLine(); if (!pixmap.ReadPixMap(Log)) ERROR_ABORT(ERROR_PIXEL) Log.getNextSection(); } if (Log.isSection("PULSE")) { Log.getNextLine(); if (!pixmap.ReadPulseHeight(Log)) ERROR_ABORT(ERROR_PH) Log.getNextSection(); } if (Log.isSection("PH1")) { Log.getNextLine(); if (!pixmap.ReadPulseHeight1(Log)) ERROR_ABORT(ERROR_PH1) Log.getNextSection(); } if (Log.isSection("PH2")) { Log.getNextLine(); if (!pixmap.ReadPulseHeight2(Log)) ERROR_ABORT(ERROR_PH2) Log.getNextSection(); } // read [PUCn] sections if exist if (Log.isSection("PUC1")) { // read [PUC1] section Log.getNextLine(); if (!pixmap.ReadRefLevel(Log)) ERROR_ABORT(ERROR_PUC) Log.getNextSection(); // read [PUC2] section if (!Log.isSection("PUC2")) ERROR_ABORT(ERROR_PUC) Log.getNextLine(); if (!pixmap.ReadLevel(Log,3)) ERROR_ABORT(ERROR_PUC) Log.getNextSection(); // read [PUC3] section if (!Log.isSection("PUC3")) ERROR_ABORT(ERROR_PUC) Log.getNextLine(); if (!pixmap.ReadLevel(Log,2)) ERROR_ABORT(ERROR_PIXEL) Log.getNextSection(); // read [PUC4] section if (!Log.isSection("PUC4")) ERROR_ABORT(ERROR_PUC) Log.getNextLine(); if (!pixmap.ReadLevel(Log,1)) ERROR_ABORT(ERROR_PUC) Log.getNextSection(); // read [PUC5] section if (!Log.isSection("PUC5")) ERROR_ABORT(ERROR_PUC) Log.getNextLine(); if (!pixmap.ReadLevel(Log,0)) ERROR_ABORT(ERROR_PUC) Log.getNextSection(); pixmap.levelExist = true; } // read [CLASS] section if (Log.isSection("CLASS")) { if (sscanf(Log.getNextLine(),"%i", &logChipClass)!=1) ERROR_ABORT(ERROR_CLASS) Log.getNextSection(); } // read [POFF] section if (!Log.isSection("POFF")) ERROR_ABORT(ERROR_POFF) if (sscanf(Log.getNextLine(),"%i", &bin)!=1) ERROR_ABORT(ERROR_POFF) Log.getNextSection(); // read [END] section if (!Log.isSection("END")) ERROR_ABORT(ERROR_END) Log.getNextLine(); if (strlen(Log.getLine())<12) ERROR_ABORT(ERROR_END) strncpy(endTime,Log.getNextLine()+5,24); Log.getNextSection(); return true; } bool operator>(CChip &a, CChip &b) { if (a.picY > b.picY) return true; if ((a.picY==b.picY) && (a.picX>b.picX)) return true; return false; } inline bool operator==(CChip &a, CChip &b) { return (a.picY == b.picY) && (a.picX == b.picX); } void CChip::SetAoutOffset(double offset) { int iOffset = int(offset); if (black.exist) { black.mean -= offset; black.min -= iOffset; black.max -= iOffset; } if (ublack.exist) { ublack.mean -= offset; ublack.min -= iOffset; ublack.max -= iOffset; } for (int i=0; i<6; i++) if (l[i].exist) { l[i].mean -= offset; l[i].min -= iOffset; l[i].max -= iOffset; } } void CChip::Calculate() { // set pic coordinates if (mapX!=0 || mapY!=0) { picX = 2*mapX + mapPos%2 + 1; picY = 2*mapY - mapPos/2 + 2; } else { picX = picY = 0; } double blackLevel = black.mean; addressStep = (black.exist && ublack.exist) ? (black.mean-ublack.mean)/4 : -1.0; n = 0; pm = 0.0; pm_col_max = 0.0; pstd = 0.0; pmin = 100; pmax = 0; if (bin==13) bin = 0; nPixDefect = 0; nPixNoSignal = 0; nPixNoisy = 0; nPixUnmaskable = 0; nPixAddrDefect = 0; nPixNoTrim = 0; nPixThrOr = 0; int col, row, sum = 0, sum2 = 0; for (col=0; col<52; col++) for (row=0; row<80; row++) { if (pixmap.GetMaskedCount(col,row) > 0) nPixUnmaskable++; if (pixmap.GetUnmaskedCount(col,row) == 0) nPixNoSignal++; else if (pixmap.GetUnmaskedCount(col,row) > 1) nPixNoisy++; if (pixmap.GetDefectAddrCode(col,row)) nPixAddrDefect++; if (pixmap.GetDefectTrimBit(col,row)) nPixNoTrim++; if (pixmap.IsDefect(col,row)) { nPixDefect++; continue; } int y = pixmap.GetRefLevel(col,row); if (y < 100) { n++; sum += y; sum2 += y*y; if (y<pmin) pmin = y; if (y>pmax) pmax = y; } } if (n>0) { pm = double(sum)/n; pstd = sqrt(double(sum2)/n - pm*pm); int n_col; double pm_col[52]; for (col=0; col<52; col++) { n_col = 0; pm_col[col] = 0.0; int pcolsum = 0; for (row=0; row<80; row++) if (!pixmap.IsDefect(col,row)) { n_col++; pcolsum += pixmap.GetRefLevel(col,row); } if (n_col>0) pm_col[col] = (double)pcolsum/n_col; else break; } if (n_col>0) for (col=1; col<52; col++) { double pm_col_diff = fabs(pm_col[col] - pm_col[col-1]); if ((col==1) || (col==51)) pm_col_diff /= 3.0; if (pm_col_diff > pm_col_max) pm_col_max = pm_col_diff; } #define PMAX 15 for (col=0; col<52; col++) for (row=0; row<80; row++) { int y = pixmap.GetRefLevel(col,row); if (y == 100) nPixThrOr++; else if (y < (pm-PMAX) || (pm+PMAX) < y) nPixThrOr++; } } nColDefect = 0; for (col=0; col<26; col++) if (dcol.get(col)) nColDefect++; // pulse height #define PH1TOL 90 #define PH21TOL 60 nPh = 0; nPhFail = 0; int sum1=0, sum1_2=0, sum21 = 0, sum21_2=0; if (pixmap.pulseHeight1Exist && pixmap.pulseHeight2Exist) { for (col=0; col<52; col++) for (row=0; row<80; row++) { int ph1 = pixmap.GetPulseHeight1(col,row); int ph2 = pixmap.GetPulseHeight2(col,row); if (ph1<10000 && ph2<10000) { nPh++; sum1 += ph1; sum1_2 += ph1*ph1; sum21 += ph2-ph1; sum21_2 += (ph2-ph1)*(ph2-ph1); } } if (nPh>0) ph1mean = double(sum1)/nPh; ph21mean = double(sum21)/nPh; ph1std = sqrt(double(sum1_2)/nPh - ph1mean*ph1mean); ph21std = sqrt(double(sum21_2)/nPh - ph21mean*ph21mean); for (col=0; col<52; col++) for (row=0; row<80; row++) { int ph1 = pixmap.GetPulseHeight1(col,row); int ph2 = pixmap.GetPulseHeight2(col,row); if (ph1<10000 && ph2<10000) { int phdiff = ph2-ph1; if (ph1<(ph1mean-PH1TOL) || ph1>(ph1mean+PH1TOL) || phdiff<(ph21mean-PH21TOL) || phdiff>(ph21mean+PH21TOL)) nPhFail++; } } } if (nPixThrOr > nPixDefect) nPixDefect = nPixThrOr; if (nPhFail > nPixDefect) nPixDefect = nPhFail; // === chip classification =========================================== #define CHIPFAIL(code) { failCode = (code); return; } failCode = FAIL_NOFAIL; // --- class 5 ------------------------------------------------------- chipClass = pickClass = 5; if (bin == 1) CHIPFAIL(FAIL5_BIN1) if (bin == 2) CHIPFAIL(FAIL5_BIN2) if (bin == 3) CHIPFAIL(FAIL5_BIN3) if (bin == 4) CHIPFAIL(FAIL5_BIN4) if ((bin == 5) && (nPixDefect>=4000)) CHIPFAIL(FAIL5_DEF) // --- class 4 ------------------------------------------------------- chipClass = pickClass = 4; if (nColDefect > 0) CHIPFAIL(FAIL4_COL) if (nPixDefect > 40) CHIPFAIL(FAIL4_PIXNUM) if (nPixThrOr > 40) CHIPFAIL(FAIL4_PIXNUM) if (nPixUnmaskable > 0) CHIPFAIL(FAIL4_MASK) if (nPixAddrDefect > 0) CHIPFAIL(FAIL4_ADDR) if ( 65.0 < IdigOn) CHIPFAIL(FAIL4_IDON) if ( 65.0 < IanaOn) CHIPFAIL(FAIL4_IAON) if (IdigInit < 20.0 || 40.0 < IdigInit) CHIPFAIL(FAIL4_IDINIT) if (IanaInit < 10.0 || 55.0 < IanaInit) CHIPFAIL(FAIL4_IAINIT) // --- class 3 ------------------------------------------------------- chipClass = pickClass = 3; if (nPixDefect>4) CHIPFAIL(FAIL3_1PC) if (pm < 30.0 || 80.0 < pm) CHIPFAIL(FAIL3_TMEAN) if (pstd < 0.5 || 4.0 < pstd) CHIPFAIL(FAIL3_TSTD) // if (pdiff < 5 || 30 < pdiff) CHIPFAIL(FAIL3_TDIFF) if (pm_col_max > 2.5) CHIPFAIL(FAIL3_TCOL) if (ph1mean < -200.0 || 150.0 < ph1mean) CHIPFAIL(FAIL3_PHOFFS) if (ph1std > 25) CHIPFAIL(FAIL3_PHOFFS) if (ph21mean < 100.0 || 300.0 < ph21mean) CHIPFAIL(FAIL3_PHGAIN) if (ph21std > 20) CHIPFAIL(FAIL3_PHGAIN) if (addressStep < 70.0 || 110.0 < addressStep) CHIPFAIL(FAIL3_ASTEP) if (blackLevel < -12.0 || 12.0 < blackLevel) CHIPFAIL(FAIL3_BL) // --- class 2 ------------------------------------------------------- chipClass = 2; pickClass = 1; if (nPixDefect>0) CHIPFAIL(FAIL2_1PM) // --- class 1 ------------------------------------------------------- chipClass = pickClass = 1; } void CChip::PrintFailString(FILE *f) { switch (failCode) { case FAIL_NOFAIL: return; // --- class 5 ------------------------------------------------------- case FAIL5_BIN1: fprintf(f,"shortcut"); break; case FAIL5_BIN2: fprintf(f,"Id < 5 mA"); break; case FAIL5_BIN3: fprintf(f,"no token"); break; case FAIL5_BIN4: fprintf(f,"I2C"); break; case FAIL5_DEF: fprintf(f,"%i Pixel defect", nPixDefect); break; // --- class 4 ------------------------------------------------------- case FAIL4_COL: fprintf(f,"%i dcol defect", nColDefect); break; case FAIL4_PIXNUM: fprintf(f,"%i pixel defect", nPixDefect); break; case FAIL4_MASK: fprintf(f,"%i pixel not maskable", nPixUnmaskable); break; case FAIL4_ADDR: fprintf(f,"%i pixel address defect", nPixAddrDefect); break; case FAIL4_IDON: fprintf(f,"IdigOn = %0.1f mA (<65 mA)", IdigOn); break; case FAIL4_IAON: fprintf(f,"IanaOn = %0.1f mA (<65 mA)", IanaOn); break; case FAIL4_IDINIT: fprintf(f,"IdigInit = %0.1f mA (20...65 mA)", IdigInit); break; case FAIL4_IAINIT: fprintf(f,"IanaInit = %0.1f mA (10...55 mA)", IanaInit); break; // --- class 3 ------------------------------------------------------- case FAIL3_1PC: fprintf(f,"%i pixel defect (<=1%%)", nPixDefect); break; case FAIL3_TMEAN: fprintf(f,"Thrshold(mean) = %0.1f (30...80)", pm); break; case FAIL3_TSTD: fprintf(f,"Threshold(rms) = %0.2f (0.5...4.0)", pstd); break; case FAIL3_TDIFF: fprintf(f,"Threshold(max-min) = %i (5...30)", pmax-pmin); break; case FAIL3_TCOL: fprintf(f,"Threshold Col-Col = %0.2f (<2.5)", pm_col_max); break; case FAIL3_PHOFFS: fprintf(f,"Pulse height offset = %0.1f(+/-%0.1f)\n", ph1mean, ph1std); break; case FAIL3_PHGAIN: fprintf(f,"Pulse height gain = %0.1f(+/-%0.1f)\n", ph21mean, ph21std); break; case FAIL3_ASTEP: fprintf(f,"addr step = %0.1f (70...100)", addressStep); break; case FAIL3_BL: fprintf(f,"AOUT offset = %0.1f (-10...+10)", black.mean); break; // --- class 2 ------------------------------------------------------- case FAIL2_1PM: fprintf(f,"%i pixel defect", nPixDefect); break; default: fprintf(f,"undefined fail code"); } } bool CDcol::read(CScanner &Log) { int col; for (col=0; col<26; col++) dcol[col]=0; while (Log.getNextLine()[0] != 0) { if (strlen(Log.getLine())< 6) return false; if (sscanf(Log.getLine()+4,"%i", &col)!=1) return false; if (col<0 || col>=26) return false; switch(Log.getLine()[0]) { case 'w': dcol[col] |= 0x01; break; case 't': dcol[col] |= 0x02; break; case 'd': dcol[col] |= 0x04; break; default: return false; } } exist = true; return true; } CChip* CWaferDataBase::GetFirst() { CChip *p = first; while (p) { if (p->multi <= 1) return p; p = p->next; } return NULL; } CChip* CWaferDataBase::GetPrev(CChip *chip) { CChip *p = chip ? chip->prev : NULL; while (p) { if (p->multi <= 1) return p; p = p->prev; } return NULL; } CChip* CWaferDataBase::GetNext(CChip *chip) { CChip *p = chip ? chip->next : NULL; while (p) { if (p->multi <= 1) return p; p = p->next; } return NULL; } bool CWaferDataBase::Add(CChip *chip) { chip->prev = last; chip->next = NULL; if (last) last->next = chip; last = chip; if (!first) first = chip; return true; } void CWaferDataBase::DeleteAll() { CChip *p = first; while (p) { CChip *q = p; p = p->next; delete q; } first = last = NULL; } void CWaferDataBase::Swap(CChip *entry) { if (entry->next == NULL) return; CChip *p = entry->next; if (entry->prev) entry->prev->next = p; else first = p; if (p->next) p->next->prev = entry; else last = entry; entry->next = p->next; p->prev = entry->prev; entry->prev = p; p->next = entry; } void CWaferDataBase::SortPicOrder() { if (first == last) return; bool swapped; do { swapped = false; CChip *p = first; while (p && p->next) { if (*p > *(p->next)) { Swap(p); swapped = true; } p = p->next; } } while (swapped); } // chips must be sorted void CWaferDataBase::CalculateMulti() { CChip *p, *s, *best; p = first; while (p) { best = p; s = p->next; while (s) { if (!(*s == *p)) break; if (s->failCode > best->failCode) best = s; s = s->next; } while(p != s && p) { p->multi = (p == best) ? 0 : 2; p = p->next; } } } void CWaferDataBase::SetPicGroups() { if (first == NULL) return; // count groups int nGroups = 0; int nClass; for (nClass=1; nClass<=5; nClass++) { int gchip = 0; CChip *p = first; while (p) { if (p->pickClass == nClass) { p->pickGroup = nGroups+1; gchip++; if (gchip>=16) { nGroups++; gchip = 0; } } p = p->next; } if (gchip > 0) nGroups++; } } double CWaferDataBase::CorrectAoutOffset() { int n = 0; double sum = 0.0; CChip *p = GetFirstM(); while (p) { if (p->black.exist) { sum += p->black.mean; n++; } p = GetNextM(p); } if (n == 0) return 0.0; aoutOffset = sum/n; p = GetFirstM(); while (p) { p->SetAoutOffset(aoutOffset); p = GetNextM(p); } return aoutOffset; } void CWaferDataBase::Calculate() { CChip *p = GetFirstM(); while (p) { p->Calculate(); p = GetNextM(p); } } // ----------------------------------------------------------------------- bool CWaferDataBase::GeneratePickFile(char filename[]) { if (first == NULL) return false; FILE *f = fopen(filename, "wt"); if (f == NULL) return false; // count groups int nGroups = 0; int nClass; for (nClass=1; nClass<=5; nClass++) { int gchip = 0; CChip *p = GetFirst(); while (p) { if (p->pickClass == nClass) { gchip++; if (gchip>=16) { nGroups++; gchip = 0; } } p = GetNext(p); } if (gchip > 0) nGroups++; } time_t t; struct tm *dt; time(&t); dt = localtime(&t); fprintf(f, "Wafer: %s\n", first->waferId); fprintf(f,"Datum: %i.%i.%i\n", int(dt->tm_mday), int(dt->tm_mon+1), int(dt->tm_year+1900)); fprintf(f,"Gruppen: %i\n", nGroups); fprintf(f,"Kommentar: none\n\n"); fputs(" Chip#1 Chip#2 Chip#3 Chip#4 Chip#5 Chip#6 Chip#7 Chip#8" " Chip#9 Chip#10 Chip#11 Chip#12 Chip#13 Chip#14 Chip#15 Chip#16 Klasse\n" "Gruppe: X/Y X/Y X/Y X/Y X/Y X/Y X/Y X/Y" " X/Y X/Y X/Y X/Y X/Y X/Y X/Y X/Y\n",f); int group = 1; for (nClass=1; nClass<=5; nClass++) { int gchip = 0; CChip *p = GetFirst(); while (p) { if (p->pickClass == nClass) { if (gchip == 0) fprintf(f," %3i", group); fprintf(f," %2i/%-2i", p->picX, p->picY); gchip++; if (gchip>=16) { group++; gchip = 0; fprintf(f," %4i\n", nClass); } } p = GetNext(p); } if (gchip > 0) { while (gchip<16) { fputs(" ",f); gchip++; } fprintf(f," %4i\n", nClass); group++; } } fclose(f); return true; } bool CWaferDataBase::WriteXML_File(char path[], CChip &chip) { char filename[80]; char datetime[24]; if (!chip.ConvertDate(datetime)) return false; sprintf(filename, "%s\\%s_%i%i%c.xml", path, chip.waferId, chip.mapY, chip.mapX, "ABCD"[chip.mapPos]); FILE *f = fopen(filename,"wt"); if (f==NULL) return false; fputs( "<?xml version='1.0' encoding='UTF-8'?>\n" "<!DOCTYPE root []>\n" " <ROOT>\n" " <HEADER>\n" " <TYPE>\n" " <EXTENSION_TABLE_NAME>BRL_ROC_ON_WAFER_TEST</EXTENSION_TABLE_NAME>\n" " <NAME>BRL ROC On-Wafer Test</NAME>\n" " </TYPE>\n" " <RUN>\n", f); fprintf(f, " <RUN_NAME>PSI46V2 %s</RUN_NAME>\n" " <RUN_BEGIN_TIMESTAMP>%s</RUN_BEGIN_TIMESTAMP>\n", chip.waferId, datetime); fputs( " <COMMENT_DESCRIPTION>ROC On-Wafer Test</COMMENT_DESCRIPTION>\n" " <INITIATED_BY_USER>Beat Meier</INITIATED_BY_USER>\n" " </RUN>\n" " </HEADER>\n" " <DATA_SET>\n", f); fprintf(f, " <COMMENT_DESCRIPTION>Test results from PSI for %s</COMMENT_DESCRIPTION>\n" " <DATA_FILE_NAME>%s.txt</DATA_FILE_NAME>\n" " <PART_ASSEMBLY>\n" " <PARENT_PART>\n" " <NAME_LABEL>%s</NAME_LABEL>\n" " </PARENT_PART>\n" " <CHILD_UNIQUELY_IDENTIFIED_BY>\n" " <ATTRIBUTE>\n" " <NAME>BRL ROC Number</NAME>\n" " <VALUE>%i%i%c</VALUE>\n" " </ATTRIBUTE>\n" " </CHILD_UNIQUELY_IDENTIFIED_BY>\n" " </PART_ASSEMBLY>\n", chip.waferId, chip.waferId, chip.waferId, chip.mapY, chip.mapX, "ABCD"[chip.mapPos]); fputs( " <DATA>\n",f); // limit values for data base if (chip.chipClass < 0) chip.chipClass = 0; if (chip.chipClass > 9) chip.chipClass = 9; if (chip.IdigInit > 999.0) chip.IdigInit = 999.0; if (chip.IanaInit > 999.0) chip.IanaInit = 999.0; if (chip.InitVana > 255) chip.InitVana = 255; if (chip.black.exist) { if (chip.black.mean < -99.0) chip.black.mean = -99.0; else if (chip.black.mean > 99.0) chip.black.mean = 99.0; } if (chip.nPixDefect<0) chip.nPixDefect = 0; else if (chip.nPixDefect>4160) chip.nPixDefect = 4160; if (chip.nPixNoSignal<0) chip.nPixNoSignal = 0; else if (chip.nPixNoSignal>4160) chip.nPixNoSignal = 4160; if (chip.nPixUnmaskable<0) chip.nPixUnmaskable = 0; else if (chip.nPixUnmaskable>4160) chip.nPixUnmaskable = 4160; if (chip.nPixNoisy<0) chip.nPixNoisy = 0; else if (chip.nPixNoisy>4160) chip.nPixNoisy = 4160; if (chip.nPixNoTrim<0) chip.nPixNoTrim = 0; else if (chip.nPixNoTrim>4160) chip.nPixNoTrim = 4160; if (chip.nPixAddrDefect<0) chip.nPixAddrDefect = 0; else if (chip.nPixAddrDefect>4160) chip.nPixAddrDefect = 4160; if (chip.bin<0) chip.bin = 0; else if (chip.bin>99) chip.bin=99; // begin of data set fprintf(f," <CHIPCLASS>%u</CHIPCLASS>\n", chip.chipClass); fprintf(f," <CURRENT_DIG>%0.1f</CURRENT_DIG>\n", chip.IdigInit>=0 ? chip.IdigInit : 0.0); fprintf(f," <CURRENT_ANA>%0.1f</CURRENT_ANA>\n", chip.IanaInit>=0 ? chip.IanaInit : 0.0); fprintf(f," <VOLTAGE_ANA>%u</VOLTAGE_ANA>\n", chip.InitVana>=0 ? chip.InitVana : 0); fprintf(f," <AOUT_OFFSET>%0.2f</AOUT_OFFSET>\n", chip.black.exist ? double(chip.black.mean/8) : 0.0); fprintf(f," <PIXEL_DEFECT>%u</PIXEL_DEFECT>\n", chip.nPixDefect); fprintf(f," <NO_SIGNAL>%i</NO_SIGNAL>\n", chip.nPixNoSignal); fprintf(f," <MASK_DEFECT>%i</MASK_DEFECT>\n", chip.nPixUnmaskable); fprintf(f," <NOISY>%i</NOISY>\n", chip.nPixNoisy); fprintf(f," <TRIM_BIT_DEFECT>%i</TRIM_BIT_DEFECT>\n", chip.nPixNoTrim); fprintf(f," <ADDRESS_DEFECT>%u</ADDRESS_DEFECT>\n", chip.nPixAddrDefect); fprintf(f," <FLAG>%u</FLAG>\n", chip.bin); // end of data set fputs( " </DATA>\n" " </DATA_SET>\n" "</ROOT>\n", f); fclose(f); return true; } bool CWaferDataBase::GenerateXML(char path[]) { CChip *p = GetFirst(); while (p) { if (!WriteXML_File(path, *p)) return false; p = GetNext(p); } return true; } bool CWaferDataBase::GenerateErrorReport(char filename[]) { FILE *f = fopen(filename, "wt"); if (f==NULL) return false; CChip *p = GetFirst(); while (p) { if (p->chipClass > 1) { fprintf(f,"Chip %i%i%c Class %i: ", p->mapY, p->mapX, "ABCD"[p->mapPos], p->chipClass); p->PrintFailString(f); fputs("\n", f); } p = GetNext(p); } fclose(f); return true; } bool CWaferDataBase::GenerateDataTable(char filename[]) { FILE *f = fopen(filename, "wt"); if (f==NULL) return false; fprintf(f, "WAFER POS PX PY BIN C GR IDIG0 IANA0 IDIGI IANAI VDREG VDAC IANA V24 BLLVL ADSTP DC DD WB TS DB DP DPIX ADDR TRIM MASK NSIG NOIS THRO T2F T2P PCNT PMEAN PSTD PMCOL PMI PMA NPH PHFAIL PHOMEAN PHOSTD PHGMEAN PHGSTD FAIL FAILSTRING\n"); // XY4L6GT 03C 11 11 11 4 12 123.5 123.4 137.5 130.0 2.23 2.00 24.0 123 -7.5 68.2 26 26 26 26 26 26 4000 4000 4000 4000 4000 4000 4000 9 9 4000 49.3 12.00 10.56 45 64 4000 4000 100.0 20.0 100.0 101.0 10 xxxxxxxxxxxxxxxx CChip *p = GetFirst(); while (p) { fprintf(f, "%-9s %i%i%c %2i %2i %2i %i %2i %5.1f %5.1f", p->waferId, p->mapY, p->mapX, "ABCD"[p->mapPos], p->picX, p->picY, p->bin, p->pickClass, p->pickGroup, p->IdigOn, p->IanaOn); if (p->IdigInit>=0.0) fprintf(f," %5.1f", p->IdigInit); else fputs(" ",f); if (p->IanaInit>=0.0) fprintf(f," %5.1f", p->IanaInit); else fputs(" ",f); if (p->probecard.isValid) { fprintf(f," %5.2f %4.2f", p->probecard.vd_reg, p->probecard.v_dac); } else fputs(" ",f); if (p->InitVana >= 0) fprintf(f," %4.1f %3i", p->InitIana, p->InitVana); else fputs(" ",f); if (p->black.exist) fprintf(f," %5.1f", p->black.mean); else fputs(" ",f); if (p->addressStep>=0) fprintf(f," %5.1f", p->addressStep); else fputs(" ",f); if (p->dcol.IsValid()) { int nColDead = 0, nColWBC = 0, nColTS = 0, nColDB = 0, nColNoPix = 0; for (int i=0; i<26; i++) { int res = p->dcol.get(i); if (res & 0x01) nColDead++; if (res & 0x02) nColWBC++; if (res & 0x04) nColTS++; if (res & 0x08) nColDB++; if (res & 0x10) nColNoPix++; } fprintf(f," %2i %2i %2i %2i %2i %2i", p->nColDefect, nColDead, nColWBC, nColTS, nColDB, nColNoPix); } else fputs(" ",f); if (p->failCode > CChip::FAIL5_BIN4) { fprintf(f," %4i", p->nPixDefect); fprintf(f," %4i", p->nPixAddrDefect); fprintf(f," %4i", p->nPixNoTrim); fprintf(f," %4i", p->nPixUnmaskable); fprintf(f," %4i", p->nPixNoSignal); fprintf(f," %4i", p->nPixNoisy); fprintf(f," %4i", p->nPixThrOr); if (p->pixtest2) fprintf(f," %3i %3i", (p->pixtest2 >> 8)&0xff, p->pixtest2 & 0xff); else fputs(" ",f); fprintf(f," %4i", p->n); if (p->n > 0) fprintf (f," %5.1f %5.2f %5.2f %3i %3i", p->pm, p->pstd, p->pm_col_max, p->pmin, p->pmax); else fputs(" ",f); } else fputs(" ",f); if (p->chipClass < 5 && p->nPh) fprintf(f," %4i %4i %7.1f %6.1f %7.1f %6.1f", p->nPh, p->nPhFail, p->ph1mean, p->ph1std, p->ph21mean, p->ph21std); else fputs(" ",f); fprintf(f, " %3i ", p->failCode); p->PrintFailString(f); fputs("\n", f); p = GetNext(p); } fclose(f); return true; } /* wafer #chips 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 */ bool CWaferDataBase::GenerateStatistics(const char filename[]) { FILE *f = fopen(filename, "wt"); if (f==NULL) return false; CChip *p = GetFirst(); if (!p) { fclose(f); return false; } int i; int n = 0; int fail[24] = { 0 }; int cl[5] = { 0 }; fprintf(f,"wafer: %s\n", p->waferId); while (p) { fail[p->failCode]++; cl[p->chipClass-1]++; n++; p = GetNext(p); } fprintf(f,"#Chips: %4i\n#fail: ", n); for (i=0; i<24; i++) fprintf(f," %4i", fail[i]); fputs("\n%fail: ",f); for (i=0; i<24; i++) fprintf(f," %4.1f", fail[i]*100.0/n); fprintf(f,"\n#Class: "); for (i=0; i<5; i++) fprintf(f," %4i", cl[i]); fputs("\n%Class: ",f); for (i=0; i<5; i++) fprintf(f," %4.1f", cl[i]*100.0/n); fputs("\n",f); fclose(f); return true; } #define MAXBINCOUNT 25 #define WMAPX 12 #define WMAPY 12 #define WMAPOFFSX 0 #define WMAPOFFSY 0 bool CWaferDataBase::GenerateWaferMap(char filename[], unsigned int mode) { int bincount; switch (mode) { case 0: // mode 0; bin bincount = 13; break; case 1: // mode 1: fail bincount = 24; break; case 2: // mode 2: class bincount = 5; break; default: return false; } CPostscript ps; int bin, yield[MAXBINCOUNT]; for (bin=0; bin<bincount; bin++) yield[bin] = 0; if (!ps.open(filename)) return false; ps.putTempl(""); ps.putTempl("prolog_begin.tmpl"); ps.putTempl("wmap.tmpl"); ps.putTempl("prolog_end.tmpl"); CChip *p = GetFirst(); if (p) { ps.addPage(); ps.puts("LOCAL begin\n"); switch (mode) { case 1: ps.printf("/plotType(fail code)def\n"); break; case 2: ps.printf("/plotType(class)def\n"); break; default: ps.printf("/plotType(bin)def\n"); break; } ps.printf("/productId(%s)def\n", p->productId); ps.printf("/waferId(%s)def\n", p->waferId); ps.printf("/testDate(%s)def\n", p->startTime); switch (mode) { case 1: ps.printf("/legend {legend_fail} def\n"); break; case 2: ps.printf("/legend {legend_class} def\n"); break; default: ps.printf("/legend {legend_bin} def\n"); break; } } while (p) { switch (mode) { case 1: bin = p->failCode; break; case 2: bin = p->chipClass-1; break; default: bin = p->bin; } if (0<=bin && bin<bincount) yield[bin]++; p = GetNext(p); } ps.printf("/yield ["); for (bin=0; bin<bincount; bin++) ps.printf(" %i", yield[bin]); ps.printf("]def\n[\n"); p = GetFirst(); while (p) { switch (mode) { case 1: bin = COLOR_FAIL[p->failCode]; break; case 2: bin = COLOR_CLASS[p->chipClass-1]; break; default: bin = COLOR_BIN[p->bin]; } ps.printf("[%i %i %i %i]\n", bin, p->mapPos, p->mapX-WMAPOFFSX, p->mapY-WMAPOFFSY); p = GetNext(p); } ps.printf("]wafermapPage\nend showpage\n"); ps.close(); return true; }