/* Copyright Motorola, Inc. 1993, 1994, 1999 ALL RIGHTS RESERVED You are hereby granted a copyright license to use, modify, and distribute the SOFTWARE so long as this entire notice is retained without alteration in any modified and/or redistributed versions, and that such modified versions are clearly identified as such. No licenses are granted by implication, estoppel or otherwise under any patents or trademarks of Motorola, Inc. The SOFTWARE is provided on an "AS IS" basis and without warranty. To the maximum extent permitted by applicable law, MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE AND ANY WARRANTY AGAINST INFRINGEMENT WITH REGARD TO THE SOFTWARE (INCLUDING ANY MODIFIED VERSIONS THEREOF) AND ANY ACCOMPANYING WRITTEN MATERIALS. To the maximum extent permitted by applicable law, IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER (INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS) ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE. Motorola assumes no responsibility for the maintenance and support of the SOFTWARE. */ /* l2test test the L2 cache and detect all the performance monitor choices * * mo 9/10-10/19/99 * * NOTE: * the macro DEBUG can be defined in the makefile, it makes all the * functions loud, i.e. they print when they are called. * the default is #define DEBUG = * by setting #define DEBUG = -DDEBUG * the user can turn on debug * or can turn on compilation debug info by setting #define DEBUG = -g * #define DEBUG print functions names on entry to all functions */ /* the macro NOT_PPC is defined in the makefile unix target and * not defined in the makefile ppc (default) target because * NOT_PPC is for gcc generating sun executables for debug * makefile is for metaware/gcc for generating PPC executables * * #define NOT_PPC compile for unix - for debug */ /* the macro DINKR12 is defined in the makefile implied compile * for use with dink R12.0 and beyond. */ /* File name: l2test.c */ #ifndef DINKR12 /* notice if undefined DINKR12 */ /* This code is only for version of dink32 prior to Release 12.0, * which include the release R11.0.2 which use static addresses. * dink R12.0 and beyond use dynamic addresses. The addresses defined in this file depend on the locations of the functions. The addresses may be different with each version of DINK being built. Make sure the addresses matches with what are defined in the dink_dir/ref.txt before running this l2test program These addresses correspond to dink32 V11.0.2 */ /* These are the magic addresses for the DINK functions in Ver11.0.2 */ #define printf dink_printf unsigned long (*dink_printf)() = (unsigned long (*)()) 0x6b58; #endif /* DINK32R12 */ #include "l2test.h" #ifndef NOT_PPC #ifdef DINKR12 #include "../../dinkusr.h" #endif /* DINKR12 */ void smallscanf(char *, int *); /* understands one %d or %x int at a time */ #else #define smallscanf scanf /* use standard library if not ppc run */ #endif /* NOT_PPC */ unsigned long MSRRead(void); unsigned long PMC1Read(void); unsigned long PMC2Read(void); unsigned long PMC3Read(void); unsigned long PMC4Read(void); unsigned long L2CRRead(void); void MSRWrite(unsigned long); void L2CRWrite(unsigned long); void L2BackRead(unsigned long, unsigned long, unsigned long); void L2BackWrite(unsigned long, unsigned long , unsigned long); void MMCR0Init(int); void MMCR1Init(int); int MMCR0Read(void); int MMCR1Read(void); void PMC1Init(void); void PMC3Init(void); void PerCountDisable(void); int global_L2_750_invalidate(void); int global_L2_7400_invalidate(void); int global_L1data_invalidate(void); void L2cacheTest(int start_addr, int end_addr); void performMonitorTest(int start_addr, int end_addr); void prepareForTest(int start_addr, int end_addr); unsigned long BATInit(void); unsigned long HID0Init(void); unsigned long HID0Read(void); unsigned long HID0Write(int value); unsigned long cacheFlush(void); unsigned long DBATLRead(int number ); unsigned long DBATURead(int number); unsigned long IBATLRead(int number); unsigned long IBATURead(int number); void L2cacheInit(int start_addr,int end_addr); /* global variables */ int L2_enable,L2_disable=0; int L2_progress=0; /* used for logic analyser to determine progress */ int chip_type; int pmc1,pmc2,pmc3,pmc4,mmcr0,mmcr1; int monitorTest; int count, mem_size,pattern,init_mem_size,init_end_addr; /*********************************************************** * main function: * This function can be invoked by dink as a user program * (With Supervisor Privaleges is required) * Can call all the test functions. * 1. Set up dink transfer base for printf for R12.0 * or static addresses for R11.0.2 * 2. Set the msr, the bats, and the caches to known values * 3. Query the user for processor, memory address, and test type. * 3. Call prepareForTest * which does the following * 1. Initialize the L1 and L2 cache * 2. globally invalidate the L1 and L2 cache * 3. enable the L2 cache (the L1 cache is never disabled) * 4. Fill the entire L2 cache with zeros at known addresses. * specifically, the user supplied start address. * 4. Call one of the following two tests based on the user's input from step 3 above. * 1. Call the 750 l2 cache test, L2cacheTest. * which follows the corrected steps outlined in UM 9.1.5.2 * 2. Call the 7400 l2 cache test, L2cacheTest. * which follows the corrected steps outlined in Book IV 7.9. * 3. Call the 750 monitor elucidation, monitorTest. * 4. Call the 7400 monitor elucidation, monitorTest. * The original 750 User's Manual and the 7400 Book IV are incorrect: * See the l2test.readme for the correct sequence of steps **********************************************************/ main() { int choice=0; int start_addr, end_addr; #ifdef DEBUG_FULL /*=========================================================*/ int a,b; #ifdef DINKR12 set_up_transfer_base(); /* get dink transfer table address */ #endif /* DINKR12 */ printf(" Using these L2 values for the test\n"); printf(" MPC750\n"); a=MPC750_L2_DISABLE; b=MPC750_L2_ENABLE; printf("MPC750_L2_DISABLE = 0x%x\n",a); printf("MPC750_L2_ENABLE = 0x%x\n",b); a=MPC750_L2_DISABLE_G_INV; b=MPC750_L2_ENABLE_G_INV; printf("MPC750_L2_DISABLE_G_INV = 0x%x\n",a); printf("MPC750_L2_ENABLE_G_INV = 0x%x\n",b); printf(" MPC7400\n"); a=MPC7400_L2_DISABLE; b=MPC7400_L2_ENABLE; printf("MPC7400_L2_DISABLE = 0x%x\n",a); printf("MPC7400_L2_ENABLE = 0x%x\n",b); a=MPC7400_L2_DISABLE_G_INV; b=MPC7400_L2_ENABLE_G_INV; printf("MPC7400_L2_DISABLE_G_INV = 0x%x\n",a); printf("MPC7400_L2_ENABLE_G_INV = 0x%x\n",b); #else int a; #ifdef DINKR12 set_up_transfer_base(); /* get dink transfer table address */ #endif /* DINKR12 */ #endif /* DEBUG_FULL ======================================================*/ printf("Performance Monitor or L2 Cache test programs\n"); /* turn on the caches and set the dbats and ibats for this run*/ printf("Initialize the bats and HID0\n"); /* flush the caches and turn them off */ cacheFlush(); HID0Write(0x80000000); /* turn off the caches */ #ifdef DEBUG printf(" before MSR set: MSR value is 0x%x\n",MSRRead()); #endif /* DEBUG */ MSRWrite(0x00003900); /* translation off FP on*/ #ifdef DEBUG printf(" after MSR set: MSR value is 0x%x\n",MSRRead()); #endif /* DEBUG */ a=BATInit(); #ifdef DEBUG printf(" return from BATInit is 0x%x\n",a); printf(" After Bat initialization: MSR value is 0x%x\n" ,MSRRead()); for(a=0;a<4;a++) { printf(" DBAT%dU value is 0x%x\n",a,DBATURead(a)); printf(" DBAT%dL value is 0x%x\n",a,DBATLRead(a)); } for(a=0;a<4;a++) { printf(" IBAT%dU value is 0x%x\n",a,IBATURead(a)); printf(" IBAT%dL value is 0x%x\n",a,IBATLRead(a)); } printf(" before MSR set: MSR value is 0x%x\n", MSRRead()); #endif /* DEBUG */ MSRWrite(0x00003930); /* translation on FP on*/ #ifdef DEBUG printf(" after MSR set: MSR value is 0x%x\n",MSRRead()); printf(" before HID0 value is 0x%x\n",HID0Read()); #endif /* DEBUG */ a=HID0Init(); #ifdef DEBUG printf(" return from HID0Init is 0x%x\n",a); printf(" after HID0 value is 0x%x\n",HID0Read()); #endif /* DEBUG */ printf("Begin Test\n"); L2_disable=0; while(L2_disable == 0) { printf("Which PowerPC processor: 750 or 7400?\n"); smallscanf ("%d",&chip_type); printf("\nYou chose: %d\n",chip_type); switch(chip_type) { case MPC750: L2_disable=MPC750_L2_DISABLE; L2_enable=MPC750_L2_ENABLE; switch(MPC750_CACHE_SIZE) { case 0x40000: printf(" The MPC750 interposer has Quarter Megabyte of L2 Cache\n"); break; case 0x80000: printf(" The MPC750 interposer has Half Megabyte of L2 Cache\n"); break; case 0x100000: printf(" The MPC750 interposer has One Megabyte of L2 Cache\n"); break; default: printf(" The MPC750 interposer L2 Cache size is INVALID\n"); return; } monitorTest=MPC750_MAX_ENCODE; /* indicate to L2BackWrite that this is * a monitor test and this is max increment for * pmc1, pmc2, pmc3, and pmc4 for this chip */ break; case MPC7400: L2_disable=MPC7400_L2_DISABLE; L2_enable=MPC7400_L2_ENABLE; switch(MPC7400_CACHE_SIZE) { case 0x80000: printf(" The MPC7400 interposer has Half Megabyte of L2 Cache\n"); break; case 0x100000: printf(" The MPC7400 interposer has One Megabyte of L2 Cache\n"); break; case 0x200000: printf(" The MPC7400 interposer has Two Megabyte of L2 Cache\n"); break; default: printf(" The MPC7400 interposer L2 Cache size is INVALID\n"); return; } monitorTest=MPC7400_MAX_ENCODE; /* indicate to L2BackWrite that this is * a monitor test and this is max increment for * pmc1, pmc2, pmc3, and pmc4 for this chip */ break; default: printf("Invalid choice, %d, please choose 750 or 7400\n",choice); } } printf("Specify start and end address range.\n"); printf(" Range must be at least twice the size of the L2 cache\n"); printf("start_addr is:\n"); smallscanf("%x",&start_addr); printf("\n end_addr is:\n"); smallscanf("%x",&end_addr); mem_size = end_addr - start_addr; switch(chip_type) { case MPC750: if(mem_size < (2*MPC750_CACHE_SIZE) ) { printf(" ERROR: memory range less than twice the size of L2 "); printf("cache\n memory size = 0x%x, twice cache size is 0x%x\n", mem_size,(2*MPC750_CACHE_SIZE)); return 0; } break; case MPC7400: if(mem_size < (2*MPC7400_CACHE_SIZE) ) { printf(" ERROR: memory range less than twice the size of L2 "); printf("cache\n memory = 0x%x, twice cache size is 0x%x\n", mem_size,(2*MPC7400_CACHE_SIZE)); return 0; } break; default: printf("INTERNAL ERROR testing memory range\n"); return 0; } while(choice == 0) { printf("\nWhich test: 1. Performance Monitor test, 2. L2 cache test\n"); smallscanf ("%d",&choice); printf("You chose test: %d\n",choice); switch (choice) { case 1: pmc1=pmc2=pmc3=pmc4=0; /* initialize all counter codes */ prepareForTest(start_addr, end_addr); /* set up L1 and L2 caches */ performMonitorTest(start_addr, end_addr); break; case 2: if(chip_type== MPC750) { pmc1=pmc2=pmc3=pmc4=7; /* initialize performance encoding * L2 hit and miss */ } else { pmc1=33; pmc2=26; pmc3=pmc4=0; /* initialize performance encoding * L2 hit and miss */ } prepareForTest(start_addr, end_addr); /* set up L1 and L2 caches */ monitorTest=0; /* indicate to L2BackWrite that this is NOT * a monitor test and therefore do NOT * increment pmc1, pmc2, pmc3, and pmc4 */ L2cacheTest(start_addr, end_addr); break; default: printf("Invalid choice, %d, please choose 1 or 2\n",choice); choice=0; } } } /*********************************************************** * L2cacheTest: * 1. Follow the rules from 9.1.5.2 in the 750 User's Manual * 2. or Follow the rules from ?.?.?.? in the 7400 User's Manual * * * both test, L2cacheTest and performTest uses the same strategy * of initializing the L1 and L2 cache, writing and reading to memory, * and using the performance monitor. * The difference is that the * performTest varies the mmcr0 and mmcr1 encodings for all possible types * L2cacheTest only uses the appropriate encodings for L2 cache * hits and misses. */ void L2cacheTest(int start_addr, int end_addr) { if(chip_type == MPC750) { printf("\nBegin Test as described on 9.1.5.2 in the 750 Users Manual\n"); } else { printf("\nBegin Test as described on x.x.x in the 7400 Users Manual\n"); } /* disable translation, set L2CR[DO] and L2CR[TS]and perform global * invalidation of L1 and L2 data cache */ /* prepareForTest must be run before calling this routine * it sets up the L1 and L2 cache and global values * use init_mem_size so that L2 memory size should only be the * size of the L2 cache */ printf("Step 2 part 3: Use performance monitor to record hits "); printf("and misses\n"); /* set up an alternating pattern */ pattern=0xaaaaaaaa; L2BackWrite(start_addr, init_mem_size, pattern); L2BackRead(start_addr, init_mem_size, pattern); /* now alternate every other bit */ pattern=~pattern; L2BackWrite(start_addr, init_mem_size, pattern); L2BackRead(start_addr, init_mem_size, pattern); /* Walking ones test: march a 1 through the 32 bits */ pattern = 0x00000001; /* left shift because right shift is arithmetic * and would propigate the sign bit */ for(count=0;count<32;count++) { L2BackWrite(start_addr, init_mem_size, pattern); L2BackRead(start_addr, init_mem_size, pattern); pattern = pattern << 1; } printf("Step 3: L2 cache tag memory\n"); printf(" Step 3: part 1 already done above\n"); printf(" Step 3: part 2a,b,c already done above\n"); printf(" Step 3: part 2d and e: read/write outside of L2 set up range\n"); /* write outside preset L2 cache range */ printf("Write outside the L2 range, we should get misses\n"); start_addr=start_addr+init_mem_size; init_mem_size =0x1000; pattern = 0x10101010; if( (2*L2TESTOUTRANGE_LOOP*0x1000) > (mem_size - init_mem_size) ) { printf("Memory size is not sufficient for the out of cache test\n"); return; } /* generate misses on writes and hits on reads */ for(count=0;count MPC750_MAX_ENCODE) break; /* only test till all * performance monitor * encodings are used */ } else /* MPC7400 */ { if(pmc1 > MPC7400_MAX_ENCODE) break; /* only test till all * performance monitor * encodings are used */ } L2BackWrite(start_addr, init_mem_size, pattern); L2BackRead(start_addr, init_mem_size, pattern); pattern = pattern << 1; } printf("Step 3: L2 cache tag memory\n"); printf(" Step 3: part 1 already done above\n"); printf(" Step 3: part 2a,b,c already done above\n"); printf(" Step 3: part 2d and e: read/write outside of L2 set up range\n"); /* write outside while incrementing the pmc guys */ printf("Write outside the L2 range, read all performance montior values\n"); pmc1=pmc2=pmc3=pmc4=0; start_addr=start_addr+init_mem_size; init_mem_size =0x1000; pattern = 0x10101010; if( (monitorTest*0x1000) > (mem_size - init_mem_size) ) { printf("Memory size is not sufficient for the out of cache test\n"); return; } for(count=0;count in L2BackRead\n"); #endif /* DEBUG */ mis_count = 0; /* initialize the L2 cache hit and mis counters */ PMC1Init(); #ifdef DEBUG printf("return from PMC1Init\n"); #endif /* DEBUG */ MMCR0Init(mmcr0); #ifdef DEBUG printf("return from MMCR0Init\n"); #endif /* DEBUG */ PMC3Init(); #ifdef DEBUG printf("return from PMC3Init\n"); #endif /* DEBUG */ MMCR1Init(mmcr1); #ifdef DEBUG printf("return from MMCR1Init\n"); #endif /* DEBUG */ #ifndef NOT_PPC #ifdef DEBUG printf(" Starting loop: test_addr is 0x%x, mem_size is 0x%x, pat is 0x%x\n", tst_adr, tst_size, pat); #endif /* DEBUG */ for (longi = 0; longi < tst_size; longi += 0x4) { val_read = *(unsigned long *) (tst_adr + longi); if (val_read != pat) mis_count++; } #else printf(" test_addr is 0x%x, mem_size is 0x%x, pat is 0x%x\n", tst_adr, tst_size, pat); #endif /* NOT_PPC */ PerCountDisable(); printf(" - Read: Addr range: 0x%x..", tst_adr); printf("0x%x, pattern is 0x%x\n", tst_adr+tst_size,pat); printf(" PMC1= 0x%-8x ", PMC1Read() ); printf(" PMC2= 0x%-8x ", PMC2Read() ); printf(" PMC3= 0x%-8x ", PMC3Read() ); printf(" PMC4= 0x%-8x ", PMC4Read() ); printf(" Mis-matched= 0x%x\n", mis_count); } /*********************************************************** */ void L2BackWrite(unsigned long test_addr, unsigned long mem_size, unsigned long pat) { unsigned long longi, address; int pmc1_selector, pmc2_selector,temp; int pmc3_selector, pmc4_selector; #ifdef DEBUG printf(" => in L2BackWrite\n"); #endif /* DEBUG */ /* initialize the L2 cache hit and miss counters */ pmc1 = pmc1 & 0x0000007f; /* get only 7 significant bits */ pmc2 = pmc2 & 0x0000007f; /* get only 7 significant bits */ pmc3 = pmc3 & 0x0000001f; /* get only 5 significant bits */ pmc4 = pmc4 & 0x0000001f; /* get only 5 significant bits */ mmcr0=(pmc1<<6)+pmc2; mmcr1=(pmc3<<5)+pmc4; mmcr1= mmcr1<<22; /* move bit 31 to position 9 */ PMC1Init(); #ifdef DEBUG printf("return from PMC1Init\n"); #endif /* DEBUG */ MMCR0Init(mmcr0); #ifdef DEBUG printf("return from MMCR0Init, value is: 0x%x\n", MMCR0Read()); #endif /* DEBUG */ PMC3Init(); #ifdef DEBUG printf("return from PMC3Init\n"); #endif /* DEBUG */ MMCR1Init(mmcr1); #ifdef DEBUG printf("return from MMCR1Init, value is: 0x%x\n", MMCR1Read()); #endif /* DEBUG */ #ifndef NOT_PPC #ifdef DEBUG printf(" Starting loop: test_addr is 0x%x, mem_size is 0x%x, pat is 0x%x\n", test_addr, mem_size, pat); #endif /* DEBUG */ temp=MMCR0Read(); pmc2_selector=(temp & 0x0000003f); pmc1_selector=(temp & 0x00001fc0)>>(32-26); temp=MMCR1Read(); pmc3_selector=(temp & 0xf8000000)>>(32-5); pmc4_selector=(temp & 0x07c00000)>>(32-10); printf("%d-%d-%d-%d: Values for this run will be:PMC1-PMC2-PMC3-PMC4 selector\n", pmc1_selector,pmc2_selector,pmc3_selector,pmc4_selector); printf(" MMCR0 0x%x, MMCR1 0x%x, PMC1 0x%x, PMC3 0x%x\n", MMCR0Read(), MMCR1Read(), PMC1Read(), PMC3Read()); for (longi = 0; longi < mem_size; longi += 0x4) { address = test_addr + longi; *(unsigned long *)(address) = pat; } #else printf(" test_addr is 0x%x, mem_size is 0x%x, pat is 0x%x\n", test_addr, mem_size, pat); #endif /* NOT_PPC */ #ifdef DEBUG printf("ending loop\n"); #endif /* DEBUG */ PerCountDisable(); printf(" - Write: Addr range: 0x%x..", test_addr); printf("0x%x, pattern is 0x%x\n", test_addr+mem_size,pat); printf(" PMC1= 0x%-8x ", PMC1Read() ); printf(" PMC2= 0x%-8x ", PMC2Read() ); printf(" PMC3= 0x%-8x ", PMC3Read() ); printf(" PMC4= 0x%-8x \n", PMC4Read() ); if(monitorTest != 0) { /* increment the monitor test values to the next monitor encoding */ pmc1++;pmc2++;pmc3++;pmc4++; /* increment all to next value */ } } /**************************************************************************** * prepareForTest * Follow the steps to global invalidate L1 and L2 cache * flush L1 cache * enable L2 cache * * Basically prepare the L1 and L2 caches for either an L2 cache test * or testing every encoding for the Performance Monitor * * INPUT: starting address and ending address for memory test * OUTPUT: none */ void prepareForTest(int start_addr, int end_addr) { printf("Step 1: Initialize L2\n"); printf("Step 1 part 1: Set L2CR[DO] and L2CR[TS] and global invalidate\n"); L2CRWrite(L2_disable); /* use MPC750 or MPC7400 enable bit pattern * with DO and TS set */ if(chip_type == MPC7400) { count=global_L2_7400_invalidate(); #ifdef DEBUG printf("L2CR DO and TS set is 0x%x\n",L2CRRead()); printf("MPC7400 L2CR global invalidate count is: %d\n", count); #endif /* DEBUG */ } else /* MPC750 */ { count=global_L2_750_invalidate(); #ifdef DEBUG printf("L2CR DO and TS set is 0x%x\n",L2CRRead()); printf("MPC750 L2CR global invalidate count is: %d\n", count); #endif /* DEBUG */ } printf("Step 1 part 2: L1 D cache global invalidate,"); printf(" but do not turn it off\n"); global_L1data_invalidate(); printf("Step 2: Enable L2 cache and test\n"); L2CRWrite(L2_enable); /* use MPC750 or MPC7400 enable bit pattern*/ printf("Step 2 part 1: dcbz and dcbf to initalize L2 cache and "); printf("turn off L2CR[Ts] \n"); if(chip_type == MPC7400) { init_mem_size=MPC7400_CACHE_SIZE; /* 7400 half meg cache size */ } else { /*MPC750*/ init_mem_size=MPC750_CACHE_SIZE; /* 750 half meg cache size */ } if (init_mem_size > mem_size ) { printf("ERROR, not enough available memory, size is 0x%x\n", mem_size); return; } init_end_addr=start_addr+init_mem_size; #ifdef DEBUG printf("About to call L2cacheInit with start_addr ="); printf("0x%x end_addr = 0x%x\n", start_addr,init_end_addr); #endif /* DEBUG */ L2cacheInit(start_addr,init_end_addr); /* do not turn off the D1 cache, i.e. leave it on */ printf("Step 2 part 2: leave L1 cache on and read/write patterns to L2 cache \n"); }