/*********************************************************************** Updated: 3/14/00 mo Purpose: To initialize the MPC60x/MPC750 and perform rudimentary memory/cache test. These tests are not meant to be exhaustive. They are a simple check that can be used to determine if things are getting written into memory and cache as expected. They do not test all the different possible combinations of BAT-mapped cache-inhibited regions, write- through and write back modes, cache sizes, etc. NOTE: This code will only test L1 cache. The sizes of the data accesses needs to be increased if testing L2. Also, this code only tests data cache - instruction cache is a different beast since it's not allowed to contain modified data. Register and Memory usage: registers r13, r3, and r4 have special uses - don't use them for anything else. R13 - holds address of location for current test result R3 - holds lr value for the entire cache test routine R4 - holds lr value for individual routines that call bl to branch elsewhere This test uses memory regions from 0x0009a000 - 0x0009a020 and 0x000a0000 to 0x000b0000. This code is meant to be run shortly after a hard reset when the caches are marked invalid and address translation is enabled. The caches are also marked invalid on power-on or hard reset. Modifications are necessary to put the caches and MMU into the correct state if this code is not run from hard reset. Results: Result values are: 0x10101010 indicates passed the test 0x11111111 indicates failed the test The location of the result values are as follows: Write Through Test 1 0x0009a000 Write Through Test 2 0x0009a004 Write Through Test 3 0x0009a008 Write Back Test 1 0x0009a010 Write Back Test 2 0x0009a014 Write Back Test 4 0x0009a018 Patterns are: zero: all zeros neg: the negative value of the address of the data Algorithm: 1. system_reset: Save the lr and dbat1, which is the IO area address. initialize the bats, the msr, and the hid0 register. call the cache_test_routine IF $(DINK) under control of dink then return to caller with r3=answer vector else loop in loopforever so the user and stop it and look at the results 2. cache_test_routine invalidate and enable the L2 cache put ram in write through mode Call the cache_test_1, 2, and 3 routines. Note: test 3 is for write through mode only. put ram in write back mode Call the cache_test_1, 2, and 4 routines. Note: test 4 is for write back mode only. 3. cache_test_1 Turn on and invalidate the cache fill the cache with the neg pattern. read the data verify that it is the neg pattern. 4. cache_test_2 Turn on and invalidate the cache fill the cache with the zero pattern. Turn off the cache fill the cache with the neg pattern. turn on the cache read the data verify that it is the neg pattern. because writing to memory with a disabled cache will invalidate the cache entries for those addresses. so expect the neg pattern which was written to overwrite the first pattern of zeros. 5. cache_test_3 Write through mode only Turn on and invalidate the cache fill the cache with the zero pattern. read the zero pattern and verify it fill the cache with the neg pattern. invalidate the cache read the data verify that it is the neg pattern. because write through mode will write the data to memory and the cache simultaneously 6. cache_test_4 Write back mode only Turn on and invalidate the cache (store) fill the cache with the zero pattern. flush the cache to memory read the zero pattern and verify it (store) fill the cache with the neg pattern. invalidate the cache read the data verify that it is the zero pattern. because write back mode will not write the data to memory and the cache simultaneously hence the data in the cache is lost when it is invalidated. ***********************************************************************/ #ifdef GCC_REGISTERS #include "gcc_registers.h" #endif /*GCC_REGISTERS */ .set ibat0u,528 .set ibat1u,530 .set ibat2u,532 .set ibat3u,534 .set dbat0u,536 .set dbat1u,538 .set dbat2u,540 .set dbat3u,542 .set ibat0l,529 .set ibat1l,531 .set ibat2l,533 .set ibat3l,535 .set dbat0l,537 .set dbat1l,539 .set dbat2l,541 .set dbat3l,543 .set hid0,1008 .global system_reset .global cache_test_routine system_reset: /* set up IO space and link register */ mfspr r18,dbat2u mfspr r19,dbat2l isync mflr r17 nop /* lets make sure that r0 is really 0x0 */ addis r0,0,0x0000 /* **NOTE** that we are assuming we got here from a hard reset and the MSR is in its default state, which means the MMU is disabled. If this code is being cut and pasted into an application where we are not at reset and the MMU is on, it must be turned off (by setting MSR IR and/or MSR DR to 0) before changing the values in the BAT registers!!!!! This code sequence will disable address translation: mfmsr r3 addis r4,0,0xffff ori r4,r4,0xffcf and r3,r3,r4 mtmsr r3 Also, if you're not getting here out of hard reset, then you may need to flush and/or invalidate the caches. Please refer to other code on this website for sample code. */ /* Assuming we're coming in from reset, the BATs are in an unknown state on most PPCs. Clear all the valid bits before programming the BATs */ /* This code sequence will disable address translation: */ mfmsr r3 addis r4,0,0xffff ori r4,r4,0xffcf and r3,r3,r4 mtmsr r3 addis r4,0,0x0000 mtspr ibat0u,r4 mtspr ibat1u,r4 mtspr ibat2u,r4 mtspr ibat3u,r4 mtspr dbat0u,r4 mtspr dbat1u,r4 mtspr dbat2u,r4 mtspr dbat3u,r4 mtspr ibat0l,r4 mtspr ibat1l,r4 mtspr ibat2l,r4 mtspr ibat3l,r4 mtspr dbat0l,r4 mtspr dbat1l,r4 mtspr dbat2l,r4 mtspr dbat3l,r4 isync /* now do mmu (BAT REGISTER) setup for processor. We're cache-inhibiting all regions for now, They'll be enabled later. */ /* this is the ROM mapping. */ addis r4,r0,0xfff0 /* BRPN = fff0 */ ori r4,r4,0x0021 /* Cache inhibited, RO */ addis r3,r0,0xfff0 /* BEPI = fff0 */ ori r3,r3,0x001f /* Vs=1 Vp=1, BL = 1M */ mtspr ibat0l,r4 mtspr ibat0u,r3 mtspr dbat0l,r4 mtspr dbat0u,r3 isync /* this is the local memory mapping */ addis r4,r0,0x0000 /* BRPN = 0x0000 */ ori r4,r4,0x0032 /* cache inhibited, memcoherent, RW */ addis r3,r0,0x0000 /* BEPI = 0x0000 */ ori r3,r3,0x0fff /* Vs=1, Vp=1, BL = 256M */ mtspr ibat1l,r4 mtspr ibat1u,r3 mtspr dbat1l,r4 mtspr dbat1u,r3 isync /* now let's turn on instruction and data address translation */ /* so our MMU setup will be functional */ mfmsr r3 ori r3,r3,0x0030 mtmsr r3 isync /* set hid0 so that caches are off, instruction fetches are enabled, and if you're on a 604, enable BHT */ addis r4,0,0x0000 ori r4,r4,0x0084 mtspr hid0,r4 isync bl cache_test_routine /* restore the IO data area in the dbat */ mtspr dbat2u,r18 mtspr dbat2l,r19 isync sync lis r3,0x0009 ori r3,r3,0xa000 /* return address for answers */ mtlr r17 /* restore link register */ #ifdef DINK blr #else loopforever: b loopforever /* return to dink */ #endif /*********************************************************************** Purpose: These routines test that the caches are functioning and that code runs properly with them on. Returns: ***********************************************************************/ cache_test_routine: mflr r3 nop bl invalidate_and_enable_L1_cache nop bl put_ram_in_wt nop /* where to store the results of this test? Set in R13 before running each test as follows: Write Through Test 1 0x0009a000 Write Through Test 2 0x0009a004 Write Through Test 3 0x0009a008 Write Back Test 1 0x0009a010 Write Back Test 2 0x0009a014 Write Back Test 4 0x0009a018 */ addis r13,r0,0x0009 ori r13,r13,0xa000 bl cache_test_1 addis r13,r0,0x0009 ori r13,r13,0xa004 bl cache_test_2 addis r13,r0,0x0009 ori r13,r13,0xa008 bl cache_test_3 sync isync /* repeat the tests in write back mode */ bl put_ram_in_wb addis r13,r0,0x0009 ori r13,r13,0xa010 bl cache_test_1 addis r13,r0,0x0009 ori r13,r13,0xa014 bl cache_test_2 addis r13,r0,0x0009 ori r13,r13,0xa018 bl cache_test_4 sync isync mtlr r3 /* restore link register */ blr /************************************************************************* Test 1: general test - makes sure data gets written into mem after use or after it is replaced in the cache - depending on whether we're write-through or write-back. Use the whole cache. *************************************************************************/ cache_test_1: /* save off the link register */ mflr r4 bl invalidate_and_enable_L1_cache /* set registers to indicate that we're going to use 32k+ of space starting at address 0x000a0000 */ andi. r0,0,0 addis r10,0,0x000a /* r10 = address */ addis r11,0,0x0001 /* r11 = size */ /* first, do a bunch of stores, filling up a chunk of RAM and the entire cache */ ct1_loop1: neg r12,r10 stw r12,0x0(r10) addi r10,r10,0x4 addic. r11,r11,-0x4 bne ct1_loop1 addis r10,r0,0x0000 addis r11,r0,0x0001 /* then do loads from different addresses - this will fill the cache with different data since the data being retrieved is not in the cache and the cache is active. */ ct1_loop2: lwz r12,0x0(r10) addi r10,r10,0x4 addic. r11,r11,-0x4 bne ct1_loop2 addis r10,r0,0x000a addis r11,r0,0x0001 /* Load the data written in the first part of the loop. Regardless of whether we were WT or WB, we should get the same values we wrote */ ct1_loop3: neg r12,r10 lwz r9,0x0(r10) cmpl 0,0,r12,r9 beq cont1 /* next 2 instructions only executed if there's an error - breaks us out of this test */ bl cache_error b exit_test cont1: addi r10,r10,0x4 addic. r11,r11,-0x4 bne ct1_loop3 /* success */ bl cache_success b exit_test /* each test executes this when done to restore lr and return */ exit_test: /* flush the cache to be sure result ends up in mem */ dcbf r0,r13 mtlr r4 blr /***************************************************************** Test 2: Test that all data loads with the cache on turn the cache off and write to the same memory locations, which will invalidate those addresses in the cache For this test, use an 16k test size - we don't want to overwrite any cached date by wrapping around ******************************************************************/ cache_test_2: /* save off the link register */ mflr r4 /* make sure the cache is active */ bl invalidate_and_enable_L1_cache /* start address = 0x000a0000, size = 16k */ addis r10,r0,0x000a /* r10 = address */ addi r11,r0,0x4000 /* r11 = size */ addis r12,r0,0x0000 ct2_loop1: /* fill up 16k of mem with zero values, expecting this to get cached */ stw r12,0x0(r10) addi r10,r10,0x4 addic. r11,r11,-0x4 bne ct2_loop1 /* disable the cache */ bl cache_inhibit addis r10,r0,0x000a addi r11,r0,0x4000 /* write new values to the same address space, bypassing the cache */ ct2_loop3: neg r12,r10 stw r12,0x0(r10) addi r10,r10,0x4 addic. r11,r11,-0x4 bne ct2_loop3 /* re-activate cache */ bl invalidate_and_enable_L1_cache addis r10,r0,0x000a addi r11,r0,0x4000 /* now that the cache is back on, do loads from the addresses just written. Since the cache is on, loads will use data in the cache, which should be the data from ct2_loop3.*/ ct2_loop5: neg r12,r10 lwz r9,0x0(r10) cmpl 0,0,r12,r9 beq cont2 /* next 2 instructions only executed if there's an error - breaks us out of this test */ bl cache_error b exit_test cont2: addi r10,r10,0x4 addic. r11,r11,-0x4 bne ct2_loop5 /* success */ bl cache_success b exit_test /************************************************************************ Test 3: Write though mode only, invalidate the cache and ensure that new data was written to memory and cache. *************************************************************************/ cache_test_3: /* save off the link register */ mflr r4 bl invalidate_and_enable_L1_cache /* start address = 0x000a0000, size = 16k */ addis r10,r0,0x000a /* r10 = address */ addi r11,r0,0x4000 /* r11 = size = 16k */ addis r12,r0,0x0000 /* cache is on, store zeros into RAM and partially fill dcache */ ct3_loop1: stw r12,0x0(r10) addi r10,r10,0x4 addic. r11,r11,-0x4 bne ct3_loop1 /* read the zero pattern */ /* start address = 0x000a0000, size = 16k */ addis r10,r0,0x000a /* r10 = address */ addi r11,r0,0x4000 /* r11 = size = 16k */ addis r12,r0,0x0000 ct3_loop5: lwz r9,0x0(r10) cmpl 0,0,r12,r9 beq cont3 /* next 2 instructions only executed if there's an error - breaks us out of this test */ bl cache_error b exit_test cont3: addi r10,r10,0x4 addic. r11,r11,-0x4 bne ct3_loop5 /* No error so on to next part of test */ /* fill cache with neg pattern, in write through mode also write to memory */ addis r10,r0,0x000a addi r11,r0,0x4000 ct3_loop3: neg r12,r10 stw r12,0x0(r10) addi r10,r10,0x4 addic. r11,r11,-0x4 bne ct3_loop3 /* invalidate the cache */ bl invalidate_and_enable_L1_cache /* read the data and verify that it is the neg pattern */ addis r10,r0,0x000a addi r11,r0,0x4000 /* cache is now on, read data (which should read from memory) since the cache was invalidated and make sure it's the changed neg value, not the original zero value */ ct3_loop6: neg r12,r10 lwz r9,0x0(r10) cmpl 0,0,r12,r9 beq cont3a /* next 2 instructions only executed if there's an error - breaks us out of this test */ bl cache_error b exit_test cont3a: addi r10,r10,0x4 addic. r11,r11,-0x4 bne ct3_loop6 /* success */ bl cache_success b exit_test /************************************************************************ Test 4: Write back mode only, invalidate the cache and ensure that new data was not written to memory only to the cache. *************************************************************************/ cache_test_4: /* save off the link register */ mflr r4 bl invalidate_and_enable_L1_cache /* start address = 0x000a0000, size = 16k */ addis r10,r0,0x000a /* r10 = address */ addi r11,r0,0x4000 /* r11 = size = 16k */ addis r12,r0,0x0000 /* cache is on, store zeros into RAM and partially fill dcache */ ct4_loop1: stw r12,0x0(r10) addi r10,r10,0x4 addic. r11,r11,-0x4 bne ct4_loop1 /* read the zero pattern */ /* start address = 0x000a0000, size = 16k */ addis r10,r0,0x000a /* r10 = address */ addi r11,r0,0x4000 /* r11 = size = 16k */ addis r12,r0,0x0000 ct4_loop5: lwz r9,0x0(r10) cmpl 0,0,r12,r9 beq cont4 /* next 2 instructions only executed if there's an error - breaks us out of this test */ bl cache_error b exit_test cont4: addi r10,r10,0x4 addic. r11,r11,-0x4 bne ct4_loop5 /* Flush the cache, write all those zeros to memory */ addis r10,r0,0x000a addi r11,r0,0x4000 ct4_loop2: dcbf r0,r10 addi r10,r10,0x4 addic. r11,r11,-0x4 bne ct4_loop2 /* No error so on to next part of test */ /* fill cache with neg pattern, in write through mode also write to memory */ addis r10,r0,0x000a addi r11,r0,0x4000 ct4_loop3: neg r12,r10 stw r12,0x0(r10) addi r10,r10,0x4 addic. r11,r11,-0x4 bne ct4_loop3 /* invalidate the cache */ bl invalidate_and_enable_L1_cache /* read the data and verify that it is the zero pattern */ addis r10,r0,0x000a addi r11,r0,0x4000 addis r12,r0,0x0000 /* cache is now on, read data (which should read from memory) since the cache was invalidated and make sure it's the original zero value, not the changed neg value */ ct4_loop6: lwz r9,0x0(r10) cmpl 0,0,r12,r9 beq cont4a /* next 2 instructions only executed if there's an error - breaks us out of this test */ bl cache_error b exit_test cont4a: addi r10,r10,0x4 addic. r11,r11,-0x4 bne ct4_loop6 /* success */ bl cache_success b exit_test /************************ worker routines ***************************/ cache_inhibit: /* to cache inhibit we are just going to turn off the caches */ mfspr r10, hid0 addis r11,r0,0xffff ori r11,r11,0x3fff and r10,r10,r11 sync isync mtspr hid0,r10 sync blr invalidate_and_enable_L1_cache: /* turn on the caches */ mfspr r15,hid0 ori r15,r15,0xcc00 sync isync mtspr hid0,r15 isync /* if we happen to be on a 603e, we have to clear the invalidate bits */ addis r16,0,0xffff ori r16,r16,0xf3ff and r16,r16,r15 sync isync mtspr hid0,r16 isync blr cache_activate: /* turn on the caches */ mfspr r15,hid0 ori r15,r15,0xc000 mtspr hid0,r15 isync blr address_translation_on: mfmsr r15 ori r15,r15,0x0030 mtmsr r15 isync blr address_translation_off: mfmsr r15 addis r16,0,0xffff ori r16,r16,0xffcf and r15,r15,r16 sync mtmsr r15 sync blr /* make RAM write through */ put_ram_in_wt: /* save link register */ mflr r4 bl cache_inhibit bl address_translation_off /* we can do this because we are in a 1:1 */ /* translation (ie. physical mode won't kill us */ /* value for bat1u */ addis r10,r0,0x0000 ori r10,r10,0x0fff /* value for dbat1l */ addis r11,r0,0x0000 ori r11,r11,0x0042 /* Note - don't try to write to the W bit for instruction cache - this is boundedly undefined (you can't make something write-through that isn't supposed to be written. Just enable caching for the instruction space */ /* value for ibat1l */ /* don't change the ibats at all * addis r12,r0,0x0000 * ori r12,r12,0x0002 * * * mtibatl 1,r12 * mtibatu 1,r10 * isync */ /* data bat */ mtdbatl 1,r11 mtdbatu 1,r10 isync bl address_translation_on bl invalidate_and_enable_L1_cache mtlr r4 blr /* put ram section in copy back mode */ put_ram_in_wb: mflr r4 bl cache_inhibit bl address_translation_off /* we can do this because we are in a 1:1 */ /* translation (ie. physical mode won't kill us */ /* value for bat1u */ addis r10,r0,0x0000 addi r10,r10,0x0fff /* value for bat1l */ addis r11,r0,0x0000 addi r11,r11,0x0002 /* instruction bat */ mtibatl 1,r11 mtibatu 1,r10 isync /* data bat */ mtdbatl 1,r11 mtdbatu 1,r10 isync bl address_translation_on bl invalidate_and_enable_L1_cache mtlr r4 blr /* indicate errors by storing all 1's to the location in r13 */ cache_error: addis r5,r0,0x1111 ori r5,r5,0x1111 stw r5,0(r13) blr /* store 10101010 to indicate success */ cache_success: addis r5,r0,0x1010 ori r5,r5,0x1010 stw r5,0(r13) blr