#include "box.h" #include "xbert.h" #include #include #include #include #include #include #include #include #include int XBIO; // Base address int Loaded=0; // Flag: 1:chip loaded. 2:Pattern loaded. // 4:chip set 8:Pattern set. int Run_mode; // Current status 0:Idle 1:Starting 2:Run long Cycle; // Cycle count int Errcnt; // Count of link errors int Burst,Burstcnt; // Error burst status int Fatal; // Count of really bad things long PMaskM,PMaskS,PMaskI; // Pattern Masks int Offset,Davbit,Clkbit; // Pattern Flags int DavOffset; // Dav Offset int Pat_Invert; // Invert pattern at receiver int XRmask; // 1=Xonly 2=Ronly 3=Normal(both) long Status; // Most recent device status registers long DataX, DataR; // Most recent device data registers long Gpo; // Most recent GPO setting X|(R<<16) time_t Ltime; // Time of last log print (current time) time_t Ttime,Etime; // Time of Test start / Last Error long Clock; // Clock configuration int Port; // For supporting multiple control ports int ScreenH; // Screen Height int CmdX; // Current column in Cmd window struct { long F,M; } // Startup handshake structure Handshake[16]; // Flags,Masks int Handi=0,Hands; // Index into Handshake int Hstep=0; // Sigle step or pause handshake char FlagName[32][16]; // Name of flag (Used for display) long FlagPol=0; // Polarity of flags (Used for display) long FlagMask[32]= // Bit mask of flag (Used for display) {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; FILE *Cmd, *Log; char XChip[80],RChip[80], // File Names PChip[80],CmdFile[80], Pat_file[80],Log_file[80]; char *Clkwords[10]= // Used in parsing and display { "dav_free","dav_hold","one_edge","two_edge", "sync","async","rising","falling","xtal","pll" } ; char *Patwords[6]= // Used in parsing { "=random","=seq","=alt","=pspike","=nspike","=a5" } ; unsigned long huge Ptrn[32768L]; int NSamples; // Histogram stuff int Ones[34], Zeros[34]; char Plog_S[80]; void Plog(char *S) // Move to LOG window and print { struct tm * Tm; // Attach a time stamp to each line char L[16]; time_t T = time(NULL); Tm = localtime(&T); W_Log; sprintf(L,"%2.2d%2.2d %2.2d:%2.2d:%2.2d", Tm->tm_mon+1,Tm->tm_mday,Tm->tm_hour,Tm->tm_min,Tm->tm_sec); cprintf("\n%s %s",L,S); if (Log != NULL) fprintf(Log,"%s %s\n",L,S); W_Cmdx; } void Hist_Clear(void) { int I; for (I=34; I--;) { Ones[I]=0; Zeros[I]=0; } NSamples=0; } void Hist_Add(long Expect, long Was, long S) { int I; long One= Was & ~Expect; long Zero= Expect & ~Was; ++NSamples; if (S&0x00000200L) ++Ones[32]; if (S&0x02000000L) ++Ones[33]; for (I=0; I<32; ++I) { if (One&1) ++Ones[I]; if (Zero&1) ++Zeros[I]; One >>= 1; Zero >>= 1; } } void Hist_Disp( void ) { char S[8000]; int I, J, N; gettext(1,1,80,50,S); window(1,1,80,50); textattr(NORMAL); clrscr(); printf("Histogram of error words. Number of errors= %d\n",NSamples); for (I=0; I<34; ++I) { N=Zeros[I]; printf("%3d",N); N= (NSamples-N)*35/NSamples; J= 35-N; while (N--) printf(" "); while (J--) printf("*"); if (I<32) printf("%2d",I); else if (I==32) printf(" T"); else printf(" R"); N= (NSamples-Ones[I])*35/NSamples; J= 35-N; while (J--) printf("*"); while (N--) printf(" "); printf("%3d\n",Ones[I]); } printf("Press return to continue\n"); getchar(); puttext(1,1,80,50,S); } unsigned short XtoI(char *S) // Convert Hex to short { unsigned short I=0; int C; while ((C=*S++) != 0) { if (C=='x') continue; if ((C -= '0') < 0) break; // Convert digits if (C<10) { I= (I<<4)|C; continue; } C= (C|0x20)-0x27; // Convert hex letters if (C<10 || C>16) break; I=(I<<4)|C; } return(I); } unsigned long XtoL(char *S) // Convert Hex to long { unsigned long I=0; int C; while ((C=*S++) != 0) { if (C=='x') continue; if ((C-='0')<0) break; // Convert digits if (C<10) { I= (I<<4)|C; continue; } C= (C|0x20)-0x27; // Convert hex letters if (C<10 || C>16) break; I=(I<<4)|C; } return(I); } void Trigger(int Dat) { int I, Trig[8]; outpw(XBIO+8,Dat); Trig[0]=inpw(XBIO); Trig[1]=inpw(XBIO+2); Trig[2]=inpw(XBIO+4); Trig[3]=inpw(XBIO+6); Trig[4]=inpw(XBIO+8); Trig[5]=inpw(XBIO+10); Trig[6]=inpw(XBIO+12); Trig[7]=inpw(XBIO+14); for (I=0; I<8; ++I) printf(" %4.4x",Trig[I]); printf(" Trig\n"); } void Set_port(int N) // Set serial port to 0-3 or local (4) { int P= (N<<5)|0x104; delay(1); // Wait to flush any outgoing data Lconfig(P); delay(1); // Set port if (N>3) {Lconfig(4); return;} // If local port: Clear errors and return Port=N; // Else save number in global SendXR(1, 0x1000); delay(1); // Hold remote transmitters Lconfig(4); // Clear Errors SendXR(1, 0); delay(1); // Start transmitters again } void NameFlag(int F, char *N) // Attach a user-supplied name to a flag { int I=F&16; // Note no errors are checked. unsigned long B=(1L)<<((long)F&(31L)); // Make bit mask while (I<30 && FlagMask[I]) ++I; FlagMask[I]= B; if (*N == '/') { FlagPol |= B; ++N; } strcpy(FlagName[I],N); if ((F&15)!=8) return; // If we specify the Link_ready flag Clock= (Clock & ~0x01000100L) | (FlagPol & 0x01000100L); SendXR(2, Clock); delay(1); // Set the inversion properly. } #define HandNames FlagNames(Handshake[Hands].M,Handshake[Hands].F) char * FlagNames(long M, long F) { static char S[256]; char *P = S; int I; for (I=0; I<32; ++I) if (M & FlagMask[I]) { if (FlagMask[I] & ~F) *P++ = '/'; P= stpcpy(P,FlagName[I]); *P++ = ' '; } *P=0; return(S); } void Set_ext(char *Name, char *Ext, int Flag) // Set file extension { char *P= 0; // If (Flag) force it while (*Name) { if (*Name=='/' || *Name=='\\') P=0; if (*Name=='.') P= Name; ++Name; } if (Flag==0 && P) return; // Extension already exists and no Flag if (P==0) P=Name; // No extension, add to end while ((*P++ = *Ext++) !=0); // Copy } void Pattern(char *Type) // Construct or read a pattern { long P,I; FILE *Pat; strcpy(Pat_file,"=none"); Loaded &= ~0xa; if (*Type != '=') // Pattern is a file { Set_ext(Type,".pat",0); if ((Pat= fopen(Type,"rb"))==NULL) { Plog1("Couldn't open pattern file [%s]",Type); return; } if (fread(Ptrn,256,512,Pat)<512) { Plog("Pattern file is wrong size"); return; } } else // Pattern is a standard type { for (I=6; I--;) if (stricmp(Type,Patwords[(int)I])==0) break; if (I<0) { Plog1("Unrecognized pattern type [%s]",Type); return; } switch (I) { case 0: // random { for (I=32768L; I--;) Ptrn[I]= rand()+(rand()<<11)+(rand()<<22); break; } case 1: // sequential { for (I=32768L; I--;) Ptrn[I]= I + ((I^0x7fff)<<15) + (I<<30); break; } case 2: // Alternate { for (I=32768L; I;) {Ptrn[--I]= -1L; Ptrn[--I]=0; } break; } case 3: // Positive spike { for (I=32768L; I--;) Ptrn[I]= 0; Ptrn[1]= -1; break; } case 4: // Negative spike { for (I=32768L; I--;) Ptrn[I]= -1L; Ptrn[0]= 0; break; } case 5: // a5 { for (I=32768L; I;) {Ptrn[--I]= 0x55555555L; Ptrn[--I]=0xaaaaaaaaL;} break; } } } // (else) // Diddle mask, clock bits, and DAV bits for (I=32768L; I--;) Ptrn[I]= (Ptrn[I] & PMaskM)|PMaskS; if (Clkbit>=0) { P= 1L<<(Clkbit&0x1f); for (I=32768L; I;) { Ptrn[--I] |= P; Ptrn[--I] &= ~P; } } if (Davbit>=0) { P= 1L<<(Davbit&0x1f); for (I=0; I<=DavOffset; ++I) { if (Davbit&0x80) Ptrn[I] |= P; else Ptrn[I] &= ~P; } if (Davbit&0x80) Ptrn[I] &= ~P; else Ptrn[I] |= P; } strcpy(Pat_file,Type); Loaded |= 8; // Set Pattern bit / Clear loaded bit } char Word[16][32]; int Parse(char *S) // Split line into words { int W=0,P=0,C; while (1) { if ((C=*S++)>32) { Word[W][P++]=C; continue; } if (P>0) { Word[W++][P]=0; P=0; } if (C!=32 && C!=9) break; } Word[W][0]=0; *(--S)=0; // Force terminator to 0 return(W); // Return numer of words } void Clink_msg(char *T, char M, int S ) { if (S&8) Plog2("%s %cbert incoming control link error.",T,M) else if (S&1) Plog2("%s Not Receiving status from %cbert.",T,M) else if (S&0x400) Plog2("%s %cbert Control link error at remote end",T,M) } long Valid_Status(char *Txt) { int I=0, Sx=0, Sr=0; while (++I<3) { if (XRmask&1) Sx=Xstat; if (XRmask&2) Sr=Rstat; if (((Sx|Sr)&0x409) == 0) return(MakeLong(Sr,Sx)); if (I==1) { Clink_msg(Txt,'T',Sx); Clink_msg(Txt,'R',Sr); } Lconfig(4); // Reset local errors SendXR(1,16); delay(100); // Reset remote errors //xx Changed delay to 100 ms } Plog("There is a fatal control link error."); Plog("Please check cable connections and power at remote modules"); ++Fatal; return(-1); } int ReadReg(int Reg, int Rx) // Rx&1= Transmit Rx&2= Receive { int I; Rx &= XRmask; if (Reg <8 || Reg >15) // Readable registers must be 8-15 { Plog1("Invalid register (%d) in ReadReg",Reg); return(-1); } I=inpw(XBIO+4); I=inpw(XBIO+12); // Clear any existing data I=XBIO+(Rx<<1); outpw(I,Reg); outpw(I,Reg); outpw(I+8,Reg); for (I=0; I<1000 && Rx; ++I) // Wait 1000 iterations { if ((Rx&1) && !(Xstat&2)) { Rx &= 2; DataX=Xdata; } if ((Rx&2) && !(Rstat&2)) { Rx &= 1; DataR=Rdata; } } if (I==1000) { Plog2("ReadReg (%d) failed. Mask=%d",Reg,Rx); return(-1); } return(0); } int Wait(int Rx) // Wait for Pbert's send FIFO to be not full { int I=32000; // Timeout after this many iterations int S; Rx &= XRmask; while (Rx && --I) { if (Rx&1) { S= Xstat; if (!(S&4)) Rx &= 2; // If Fifo not Full else if (S &= 0x408) { Clink_msg("Wait",'T',S); return(-1); } } if (Rx&2) { S= Rstat; if (!(S&4)) Rx &= 1; // If Fifo not Full else if (S &= 0x408) { Clink_msg("Wait",'R',S); return(-1); } } } if (Rx) { Plog("Pbert FIFO full stuck on: hardware failure"); return(-1); } return(0); } int xxxWait(int Rx) // Old version of Wait { int I,S; Rx &= XRmask; if (Rx&1) { for (I=32000; --I;) { if (((S= Xstat)&4)==0) break; if (S&=0x408) { Clink_msg("Wait",'T',S); return(-1); } } if (I==0) { Plog("Tbert FIFO full stuck on: hardware failure"); return(-1); } } if ((Rx&2)==0) return(0); for (I=32000; --I;) { if (((S= Rstat)&4)==0) return(0); if (S&=0x408) { Clink_msg("Wait",'R',S); return(-1); } } Plog("Rbert FIFO full stuck on: hardware failure"); return(-1); } int Loopback(int RxMask) // &1=Xmit &2=Recv &4=Local { long T[8]= { 0x12345678L, 0x9abcdef0L, 0x33333333L, 0xccccccccL, 0xaaaa5555L, 0x99999999L, 0x12345678L, 0xeeeeeeeeL }; int Sx,Wx,Rx,Fx,Ex; // Status, Write, Read, Full, Empty counters int Sr,Wr,Rr,Fr,Er; // Status, Write, Read, Full, Empty counters if (RxMask&1) Rx= Wx= 1000; // Set transfer counters else Rx= Wx= 0; if (RxMask&2) Rr= Wr= 1003; // Start at different places else Rr= Wr= 0; Fx= Ex= Fr= Er= 255; // Set retry counters disable(); // Disable interrupts while (1) // Till counters == 0 { if (Rx) { Sx= Xstat; if (Sx&8) break; // If error if (Sx&4) { if (--Fx == 0) break; } // If X-FIFO full else { SendX(8,T[Wx&7]); Fx=255; --Wx;}// Else send a word if (Sx&2) { if (--Ex == 0) break; } // If receiver empty else { if ((DataX= Xdata)!=T[Rx&7]) break; // Check data --Rx; Ex=255; } } if (Rr) { Sx=0; // Flag that there were no ximit errors Sr= Rstat; if (Sr&8) break; // If error if (Sr&4) { if (--Fr == 0) break; } // If R-FIFO full else { SendR(8,T[Wr&7]); Fr=255; --Wr;}// Else send a word if (Sr&2) { if (--Er == 0) break; } // If receiver empty else { if ((DataR= Rdata)!=T[Rr&7]) break; // Check data --Rr; Er=255; } } else if (Rx==0) break; } enable(); // Re-enable interrupts if (Rx && Sx) { ++Fatal; Rx=1000-Rx; Wx=1000-Wx; if (RxMask&4) Plog2("T-Port Local test failed after %d reads and %d writes",Rx,Wx) else Plog2("T-Port Remote test failed after %d reads and %d writes",Rx,Wx) if (Sx&8) { Plog(" Data overrun or parity error"); return(-1); } if (Fx==0) { Plog(" Full Flag stuck on"); return(-1); } if (Ex==0) { Plog(" Empty Flag stuck on"); return(-1); } if (DataX!=T[Rx&7]) { Plog2(" Data Error: expect %lx, got %lx",T[Rx&7],DataX); return(-1); } } if (Rr) { ++Fatal; Rr=1003-Rr; Wr=1003-Wr; if (RxMask&4) Plog2("R-Port Local test failed after %d reads and %d writes",Rr,Wr) else Plog2("R-Port Remote test failed after %d reads and %d writes",Rr,Wr) if (Sr&8) { Plog(" Data overrun or parity error"); return(-1); } if (Fr==0) { Plog(" Full Flag stuck on"); return(-1); } if (Er==0) { Plog(" Empty Flag stuck on"); return(-1); } if (DataR!=T[Rr&7]) { Plog2(" Data Error: expect %lx, got %lx",T[Rr&7],DataR); return(-1); } } return(0); } #define Cmp_err(Txt,E,D) \ { Plog3("Sanity: %s: Data Error: expect %lx, got %lx",Txt,E,D); \ S |= 0x100; } int Sanity_check(int Level) // Level 0: All 1: Local only { long T[8]= { 0x12345678L, 0x9abcdef0L, 0x33333333L, 0xccccccccL, 0xaaaa5555L, 0x99999999L, 0x76543210L, 0xeeeeeeeeL }; int I,S; Set_port(4); // Set to local loopback if (Loopback(7)) return(-1); if (Level) Plog("Local Loopback test passed"); // Print if local only S=0; Set_port(Port); // Check remote modules SendXR(1,0x31); // Remote= idle, erclr, adclr delay(1); // Wait for a while if (Level) return(0); // Exit if Local only check if (Valid_Status("Sanity check")==-1) return(-1); Loaded &= ~2; // Mark pattern as unloaded if (Loopback(XRmask)) return(-1); Plog("Remote Loopback test passed"); if ((Clock&4)==0) SendR(2,Clock|4); // Set receiver clock asynchronous for (I=8; --I;) // Send 8 test words to RAM { Wait(3); SendXR(6,T[I]); } delay(1); SendXR(1,0x20); // Remote= adclr for (I=8; S==0 && --I;) // Read data back { if (ReadReg(14,3)) { S=-1; break; } if (XRmask&1 && DataX != T[I]) Cmp_err("Tbert",T[I],DataX); if (XRmask&2 && (DataR ^ T[I])& PMaskM) Cmp_err("Rbert",T[I]&PMaskM,DataR&PMaskM); } if ((Clock&4)==0) SendR(2,Clock); // Set receiver clock to what it was if (S) { Plog("Remote Sanity check failed"); ++Fatal; return(0x800); } Plog("Sanity check: System appears to be working"); return(0); } FILE * OpenFile(char *Name) // Open bit file { FILE *F; Set_ext(Name,".xcf",0); if ((F= fopen(Name,"rb")) == NULL) { Plog1("Couldn't open file [%s]",Name); Loaded &= 8; } else { Plog1("Loading file %s",Name); } return(F); } int Load_bit(void) // Reset and load ORCA chips { int I,B; long Bcnt; int Isx=0, Isr=0; FILE *Fx,*Fr; int D[3]; // Data buffer if ((Fx= OpenFile(PChip))==NULL) return(-1); Lconfig(0x10); delay(1); Lconfig(0); delay(1); // Reset PBERT FPGA Bcnt=0; while (fread(&B,1,1,Fx) > 0) // Write file to device { for (I=32767; --I;) if (inpw(XBIO)&0x80) break; // FPGA ready if (I==0) { Plog1("Timeout while loading PBERT bit file (byte %ld). Check Hardware",Bcnt); Loaded &= 8; return(-1); } outpw(XBIO+8,B); ++Bcnt; } fclose(Fx); outpw(XBIO+8,0xff); // One more for luck if (Sanity_check(1)) return(-1); Plog("Pbert bit file loaded successfully."); if (XRmask&1) { if ((Fx= OpenFile(XChip))==NULL) return(-1); else Isx=1; } if (XRmask&2) { if ((Fr= OpenFile(RChip))==NULL) { if (Isx) fclose(Fx); return(-1); } else Isr=1; } Lconfig(1); delay(4); // Send break to remotes Lconfig(2); delay(2); // Disable parity while (Isx || Isr) // Send files to remote modules { if (Isx) { if (fread(D,2,3,Fx) <= 0) Isx=0; // Read three 16-bit words else { if (Wait(1)) Isx=0; outpw(XBIO+2,D[0]); outpw(XBIO+2,D[1]); outpw(XBIO+10,D[2]); } } if (Isr) { if (fread(D,2,3,Fr) <= 0) Isr=0; // Read three 16-bit words else { if (Wait(2)) Isr= 0; outpw(XBIO+4,D[0]); outpw(XBIO+4,D[1]); outpw(XBIO+12,D[2]); } } } fclose(Fx); fclose(Fr); SendXR(2,Clock|4); // Set Clock to ASYNC if ((I=Sanity_check(0))==0) Loaded |= 5; SendXR(2,Clock); // Make sure clock is up to date return(I); } int Load_pat(int Check) // Load pattern into remote modules { // (Check==1)==> Check only long I,P; // (Check==2)==> Load then check int Adr; // (Check==3)==> Check then load if necc. if (~Loaded&8) { Plog("Load_pat: No pattern has been specified"); return(-1); } while (--Check >= 0) { SendXR(1,0x31); // Make remote modules idle if ((Clock&4)==0) SendR(2,Clock|4); // Set receiver clock asynchronous delay(1); // if (Check==1) // Load pattern { for (I=0; I<32768L; ++I) // Dump the current pattern { if (Wait(3)) break; SendX(6,Ptrn[I]); P=PMaskI^Ptrn[(I+Offset)&0x7fffL]; if (Clkbit&0x80) P &= ~(1<<(Clkbit&0x1f)); SendR(6,P); } delay(1); continue; } Loaded |=2; for (I=0; I<32768L; ++I) // Check the current pattern { if (Wait(3)) break; SendX(7,Ptrn[I]); P=PMaskI^Ptrn[(I+Offset)&0x7fffL]; if (Clkbit&0x80) P &= ~(1<<(Clkbit&0x1f)); SendR(7,P); } delay(1); if ((Clock&4)==0) SendR(2,Clock); // Set receiver clock back if ((I= Valid_Status("Load_Pat"))== -1) {Loaded &= ~2; return(-1); } if (I&0x800) // If Xbert compare error { Loaded &= ~2; // Mark as un-loaded ReadReg(10,1); Adr=(int)DataX; // Fetch Address ReadReg(12,1); // Fetch Bad data Plog3("Check Tbert: Adr=%4.4x Got %8.8lx Expect %8.8lx", Adr, DataX, Ptrn[Adr]); } if (I&0x08000000L) // Check Rbert { Loaded &= ~2; ReadReg(10,2); Adr=(int)((DataR+Offset)&0x7fffL); ReadReg(12,2); P=PMaskI^Ptrn[(I+Offset)&0x7fffL]; if (Clkbit&0x80) P &= ~(1<<(Clkbit&0x1f)); Plog3("Check Rbert: Adr=%4.4x Got %8.8lx Expect %8.8lx", Adr, DataR, P); } if (Loaded&2) { Plog("Pattern check passed"); return(0); } } // While(--Check.... Plog("Pattern check failed"); return(-1); } int Make_Idle(void) { long S; int I=4; // Try 4 times while (I--) { SendXR(1,1); delay(1); if ((S= Valid_Status("Make Idle"))== -1) return(-1); if ((S&0x10001000L)==0) return(0); } if (S&0x1000) Plog("Couldn't set Tbert to idle."); if (S&0x10000000L) Plog("Couldn't set Rbert to idle."); return(-1); } void Stop(void) { float W= Cycle * 32768.0 + 1; // Word Count float H= (time(NULL)-Ttime)/3600.0; // Number of hours int D=H/24; // Number of days H-= D*24; // Remaining number of hours SendR(1,1); delay(1); SendX(1,1); Plog2("Stopped. Total test time %3d Days %6.3f Hours.",D,H); Plog3(" Total %5d Errors / %7.1e Words =%7.1e E/W", Errcnt,W,Errcnt/W); Run_mode=0; } void Draw_screen( int Level ) { int I; if (Level>0) // Redraw everything { W_Whole; textattr(OUTLINE); clrscr(); ABox(1,1,80,5, (OUTLINE<<8)|DOUBLE); gotoxy(3,1); cprintf(" Status "); ABox(1,5,80,9, (OUTLINE<<8)|DOUBLE); gotoxy(3,5); cprintf(" Configuration "); ABox(1,9,80,Log_Area,(OUTLINE<<8)|DOUBLE); gotoxy(3,9); cprintf(" Log "); W_Stat; cprintf(" TBERT:\n\r RBERT:\n\r"); cprintf(" 0 Errors / 0.0e+00 Words =0.0e-00 E/W ( 0 Days 0.00 Hours)"); gotoxy(1,1); } // Redraw static parameters, restore cursor W_Whole; textattr(TEXT); gotoxy(14,9); cprintf(" %-12s ",Log_file); W_Conf; cprintf(" Clock: %4.1f MHz ",((Clock>>16)&0x7f)/2.0 ); for (I=5; I--;) cprintf(" %-8s",Clkwords[I+I+(((int)Clock>>I)&1)] ); textattr((Loaded&1)? TEXT : DIM); // Dim for un loaded chip file cprintf("\n\r Chip: %15s / %-15s Port=%d Dev=%d\n\r", XChip,RChip,Port,((int)Clock>>4)&3); textattr((Loaded&2)? TEXT : DIM); cprintf("Pattern: %-31s Mask: %8.8lx.%8.8lx Offset: %2d", Pat_file,PMaskM,PMaskS,Offset); textattr(TEXT); W_Cmdx; } void Print_Flags(long Ss, long Sh) { int I; long M; W_Stat; gotoxy(9,1); for (I= 0; I<16; ++I) { if ((M=FlagMask[I])==0) break; textattr((M&Sh)? FLASH : (M&Ss) ? HILITE : TEXT ); cprintf(" %s",FlagName[I]); } gotoxy(9,2); for (I=16; I<32; ++I) { if ((M=FlagMask[I])==0) break; textattr((M&Sh)? FLASH : (M&Ss) ? HILITE : TEXT ); cprintf(" %s",FlagName[I]); } W_Cmdx; textattr(TEXT); } int Decode_Status(char *Txt) // Return -1 if fatal error { int I,Adr; long Ss = Valid_Status(Txt); long L,M,F; time_t T= time(NULL); CmdX=0; // Flag !=0 if window change was made if (Ss==-1) return(-1); Ss = ((Ss&0xfff0fff0L)|Gpo)^FlagPol; // Fix up Status word if (Ss != Status) // If status has changed since last { Status=Ss; if (Ss&0x0a000200L) // If error { delay(100); // xx Add this temprorqry code Ss= Valid_Status("Decode-status retry"); if ((Ss&0x0a000200L)==0) // If no error { Plog("Error appears to be due to cable, ignored"); } else { // xx Process error as normal ReadReg(10,2); Adr=((int)DataR+Offset-5)&0x7fff; // Get RBERT address register // 123456789 123456789 1234.56789 sprintf(Plog_S," --- --- -- Adr=%4.4x ",Adr); if (Ss&0x08000000L) { ReadReg(9,2); // Get RBERT error data DataR ^= PMaskI; // Invert as appropriate Hist_Add(DataR,Ptrn[Adr],Ss); sprintf(&Plog_S[26],"Got=%8.8lx Expect=%8.8lx ",DataR,Ptrn[Adr]); strncpy(&Plog_S[12],"Data",4); } if (Ss&0x00000200L) strncpy(&Plog_S[0],"Tsync",5); if (Ss&0x02000000L) strncpy(&Plog_S[6],"Rsync",5); SendM(1,0x31); // Clear Errors Plog(Plog_S); // Log error ++Errcnt; if (Run_mode==2) { Run_mode=1; Hands=0; SendM(1,0x31); delay(1); // Clear errors again if (T-Etime > 3) Burstcnt=0; // If not a burst error else if (++Burstcnt == Burst) // If first burst error { Plog("Burst error...."); // Check patterns Load_pat(3); } else if (Burstcnt == Burst+Burst) // If second burst error { Plog("Fatal burst error...."); // Declare a fatal error Burstcnt=0; ++Fatal; Stop(); } Etime=T; } } }// end if (Ss&0x0a000200) Print_Flags(Ss,0L); } // end if status change if (Run_mode==1) // If we are starting a test - do handshake { if (Handshake[Hands].M == 0) { Hstep |= 1; ++Hands; Plog1("Pause: %s",HandNames); } M= Handshake[Hands].M; F= Handshake[Hands].F; L= (F ^ Ss) & ~0xf000fL & M; Print_Flags(Ss , L); if (!L && !(Hstep & 1)) { // Handshake has matched, so set new Gpo values Gpo = ( (~M & Gpo) | (M & (F ^ FlagPol))) & 0xf000fL; SendX(1,(Gpo<<8)+128); SendR(1,(Gpo>>8)+128); Etime= T; delay(10); if (++Hands >= Handi) // If final handshake { Run_mode=2; SendXR(1,0x70); SendR(1,2); delay(1); // Start rbert and wait ReadReg(10,3); DataX= ((DataX>>14L) & 0x3cL); I= DataX-((Clock>>17)&0x3f); if (I>4 || I<-4) { Plog1("Warning: Tbert frequency measured at %2ld MHz",DataX); if (Clock & 0x10 && DataX > 16) { Plog1("Setting clock value to %d",DataX); Clock = (Clock & ~0x7f0000L) | (DataX<<17); } } DataR= ((DataR>>14L) & 0x3cL); I= DataR-((Clock>>17)&0x3f); if (I>4 || I<-4) { Plog1("Warning: Rbert frequency measured at %2ld MHz",DataR); } SendX(1,2); delay(1); } // Start tbert if (Hstep>1) // Set single step for next step { Plog1("Step: %s", HandNames); Hstep=3; } } if (T-Etime > 5 && !Hstep) { Plog1("Handshake failed: %s",HandNames); Run_mode=0; return(0); } } // Run_mode==1 if (Run_mode==2 && T>Ltime) // Update statistics line { float H,R,W; Ltime=T; H= (T-Ttime)/3600.0; // Total test time in hours I= H/24; // Number of days H-= I*24; // Remaining number of hours Ss= Rcycle; // Compute current cycle if ((Cycle & ~Ss) & 0x8000L) Cycle += 0x10000L; Cycle= (Cycle & 0xffff0000L) | (Ss & 0xffffL); W= Cycle * 32768.0 + 1; R= Errcnt/W; W_Stat; gotoxy(1,3); cprintf("%5d Errors / %7.1e Words =%7.1e E/W (%3d Days %6.3f Hours)", Errcnt, W, R, I, H); } if (CmdX) W_Cmdx; return(0); } // Decode Status void Run(void) { delay(1); SendXR(1,0x71); delay(1); // Reset remote modules Etime= Ttime= time(NULL); Run_mode=1; Hands=0; Cycle=0; Errcnt=0; Burstcnt=0; Plog2("Run %s %4.1f MHz ",Pat_file,((Clock>>16)&0x7f)/2.0); Hist_Clear(); if (Hstep>1) { Plog1("Step %s",HandNames); Hstep=3; } } void Clear(void) { Plog("Clear not implemented"); } void ComFile(char *F) // Open command file { strcpy(CmdFile,F); Set_ext(CmdFile,".xbr",0); if ((Cmd= fopen(CmdFile,"r"))==NULL) Plog1("Can't open command file %s",CmdFile) else Plog1("Reading commands from %s",CmdFile) } int main(int ARGC, char *ARGV[]) { int I,J; // General-purpose integer int Ip=0; // Input line pointer int Term=1; // Input line terminator character int C,W; float F; long L; char *Txt; // General purpose string pointer char S[80]; // General-purpose string if ((Txt= getenv("XBERT_BASE"))==NULL) { printf("XBERT_BASE environment variable not set\n"); printf("This should be set in your autoexec.bat file\n"); Pause; exit(-1); } XBIO= XtoI(Txt); if (XBIO > 0x3ff || XBIO < 100) { printf("XBERT_BASE = %x is invalid\n",XBIO); Pause; exit(-1); } textmode(C4350); { struct text_info Ti; // Find screen size gettextinfo(&Ti); ScreenH= Ti.screenheight; } // Set a bunch of default values strcpy(XChip,"=none"); strcpy(RChip,"=none"); strcpy(PChip,"pbert.brt"); strcpy(Pat_file,"=none"); strcpy(Log_file," (closed)"); *CmdFile= 0; Offset=Burst=0; XRmask=3; Davbit=Clkbit= -1; DavOffset=0; Status=0; Fatal=0; Loaded=0; PMaskM=0xffffffffL; PMaskS=0; PMaskI=0; Offset= 0; Clock= (33L<<17) | 0x14; Log= NULL; Handi=0; Draw_screen(1); // Do a full redraw of screen for (I=1; I"); Sanity_check(0); Plog("Press ENTER to continue"); cgets(S); } } if (*CmdFile==0) ComFile("xbert"); while (1) // Main loop { if (Term) // If line was input, redraw screen { Draw_screen(0); cprintf("> "); Status=0; Term=0; } if (Loaded&4) // If bit file name has been set { if (Fatal) // Handle any fatal compaints { if (Fatal > 2) { Plog("Program Halt. ---------------------------"); if (Cmd) { fclose(Cmd); Cmd=NULL; } Loaded=0; continue; } Plog("============== Attempting to re-initialize ================"); if (Load_bit()) continue; if (Load_pat(2)) continue; Fatal=0; } Decode_Status("Main Loop"); // Read devices and display status } // Accept command ----------------------------------- if (Cmd != NULL) // If redirected input { if (fgets(S,80,Cmd)==NULL){ fclose(Cmd); Cmd=NULL; continue; } Term=13; cprintf("%s\r",S); } else while (kbhit()) // If Keyboard input { if ((C=getche())<32) { if (C==BKSPACE) { putch(32); if (Ip) { --Ip; putch(8); } continue; } Term= C ? C : 0x100 | getch(); putch('\n'); putch('\r'); S[Ip]=0; Ip=0; } else S[Ip++]=C; } #define Match(Text) (!stricmp(Text,Word[0])) if (Term==0) continue; // If no line is ready if (Term==ESCAPE) continue; // If escape was pressed W=Parse(S); // Split line into words if (Term==F1_KEY || Match("help")) { More("xbert.hlp"); W_Cmd; continue; } if (Term==F4_KEY || Match("check")) { Load_pat(3); continue; } if (Term==F5_KEY || Match("stop")) { Stop(); continue; } if (Term==F6_KEY || Match("run")) { Run(); continue; } if (Term==F7_KEY || Match("clear")) { Clear(); continue; } if (Term==F8_KEY || Match("load")) { Load_pat(2); continue; } if (Term==ALT_X || Term==ALT_F4 || Match("quit") || Match("exit")) { W_Whole; gotoxy(1,ScreenH); textattr(TEXT); exit(0); } if (Term==F3_KEY || Match("step")) { if (W>1) { Hstep=0; continue; } // step off if (Hstep) { Hstep &= 2; continue; } // step Plog("Single stepping enabled, press F3 to step"); Hstep=3; continue; } if (W==0) continue; // If empty line #undef Match #define Match(Text) if (!stricmp(Text,Word[0])) Match("source") { ComFile(Word[1]); continue; } // Open command file Match("sanity") { Sanity_check(0); continue; } // Check basic operation Match("pattern"){ Pattern(Word[1]); continue; } Match("port") { Set_port(atoi(Word[1])); continue; } Match("offset") { Offset=atoi(Word[1]); continue; } Match("davbit") { Davbit=atoi(Word[1]); // Bit 7 is invert if (W>2) Davbit |= 0x80; continue; } Match("davoffset") { DavOffset=atoi(Word[1])-1; continue; } Match("clkbit") { Clkbit=atoi(Word[1]); // Bit 7 is NOCHECK if (W>2) Clkbit |= 0x80; continue; } Match("hist") { Hist_Disp(); continue; } Match("burst") { Burst=atoi(Word[1]); continue; } Match("XRmask") { XRmask=atoi(Word[1]); continue; } Match("flag") { NameFlag(XtoI(Word[1]),Word[2]); continue; } Match("new_handshake") { Handi= 0; continue; } Match("pause") { Handshake[Handi++].M=0; continue; } Match("new_flags") { for (I=32; I--; ) FlagMask[I]=0; FlagPol=0; continue; } Match("mask") { PMaskM=XtoL(Word[1]); if (W>2) PMaskS=XtoL(Word[2]); if (W>3) PMaskI=XtoL(Word[3]); continue; } Match("logfile") // Open Log file { if (W==1) { Plog("Log file closed"); fclose(Log); Log=NULL; strcpy(Log_file," (closed)"); continue; } strcpy(Log_file,Word[1]); Set_ext(Log_file,".log",0); Log= (W>2) ? fopen(Log_file,"w") : fopen(Log_file,"a"); if (Log==NULL) Plog1("Can't open log file %s",Log_file) else Plog1("Log file %s opened",Log_file); continue; } Match("chip") // Load new chip files { if (W>3) strcpy(PChip,Word[3]); if (W>2) strcpy(RChip,Word[2]); if (W>1) strcpy(XChip,Word[1]); Loaded = (Loaded & ~3) | 4 ; Load_bit(); continue; } Match("clock") // Configure clock { sscanf(Word[1],"%f",&F); if (F<16.0 || F>63.5) { Plog1("Invalid clock speed [%s]",Word[1]); continue; } I=F*2; I &= 0x7f; Clock= (Clock& ~0x007f0000L) | ((long)(unsigned)I << 16) ; while (W>2) { --W; for (I=10; I--;) if (stricmp(Word[W],Clkwords[I])==0) break; if (I<0) { Plog1("Unknown clock configuration [%s]",Word[W]); continue; } L= 1L<<(I/2); // Set bit I/2 if (I&1) Clock |= L; else Clock &= ~L; } SendXR(2,Clock); continue; } Match("dev") { I=atoi(Word[1]); Clock = (Clock & ~0x3000L) | ((I&3)<<12); // Set new device bits SendXR(2,Clock); // Send new configuration continue; } Match("read") { cprintf("Registers:"); for (I=XBIO; I>3)&6),(I&15),L); continue; } Match("get") { I= XtoI(Word[1]); ReadReg((I&15),I>>4); Plog2("T Data=%8.8lx R Data=%8.8lx",DataX,DataR); continue; } Match("list_hs") { for (I=0; I0; --W) { if ((W&7)==0) cprintf("\n\r%4.4x:",I); cprintf(" %8.8lx",Ptrn[I]); I= ++I & 0x7fff; } cprintf("\n\r"); continue; } Plog1("Unrecognized command [%s]",S); } } // Main / while