/* * init_caches.S * * Common Cache initialization */ /* Copyright (c) 2007-2018, MIPS Tech, LLC and/or its affiliated group companies or licensors All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include // #defines for GPRs #include // #defines for CP0 registers #include // #defines for ILINE_SIZE, DLINE_SIZE and HCI #define LINE_SIZE $3 #define BYTES_PER_LOOP $2 #define SET_SIZE $4 #define ASSOC $5 #define CONFIG_1 $6 #define END_ADDR $7 #define TOTAL_BYTES $12 #define CURRENT_ADDR $13 #define TEMP1 $14 #define TEMP2 $15 #define LINES_PER_ITER 8 // number of cache instructions per loop /************************************************************************************** **************************************************************************************/ LEAF(init_icache) // Can be skipped if Config7[HCI] set mfc0 TEMP1, C0_CONFIG, 7 // Read CP0 Config7 ext TEMP1, TEMP1, HCI, 1 // extract HCI bne TEMP1, zero, done_icache // Determine how big the I$ is mfc0 CONFIG_1, C0_CONFIG1 // read C0_Config1 // Isolate I$ Line Size ext LINE_SIZE, CONFIG_1, CFG1_ILSHIFT, 3 // extract IL // Skip ahead if No I$ beq LINE_SIZE, zero, done_icache li TEMP1, 2 sllv LINE_SIZE, TEMP1, LINE_SIZE // Now have true I$ line size in bytes ext SET_SIZE, CONFIG_1, CFG1_ISSHIFT, 3 // extract IS li TEMP1, 64 sllv SET_SIZE, TEMP1, SET_SIZE // I$ Sets per way // Config1IA == I$ Assoc - 1 ext ASSOC, CONFIG_1, CFG1_IASHIFT, 3 // extract IA addiu ASSOC, ASSOC, 1 li TEMP1, (LINES_PER_ITER) mul SET_SIZE, SET_SIZE, ASSOC // Total number of sets mul TOTAL_BYTES, SET_SIZE, LINE_SIZE // Total number of bytes mul BYTES_PER_LOOP, LINE_SIZE, TEMP1 // Total bytes per loop // Set the starting address at the beginning of kgeg0 (0x80000000) which will corresponds to // way 0 index 0 of the cache and position so starting address is in the // middle of the first bytes per loop because the code will use + and - offsets li CURRENT_ADDR, 0x0000000080000000 srl TEMP1, BYTES_PER_LOOP, 1 addu CURRENT_ADDR, TEMP1, CURRENT_ADDR addu END_ADDR, CURRENT_ADDR, TOTAL_BYTES // make ending address subu END_ADDR, END_ADDR, BYTES_PER_LOOP // -1 // Clear TagLo/TagHi registers mtc0 zero, C0_TAGLO // write C0_ITagLo mtc0 zero, C0_TAGHI // Note: not all implementations will have a tag Hi but writes will be ignored if not present ehb // due to offset field restrictions code assumes line size will not be more that 128 bytes for a r5 or less core // or not more than 64 bytes for a r6 and greater core next_icache_tag: // Index Store Tag Cache Op // Will invalidate the tag entry, clear the lock bit, and clear the LRF bit cache 0x8, (ILINE_SIZE*-2)(CURRENT_ADDR) cache 0x8, (ILINE_SIZE*-1)(CURRENT_ADDR) cache 0x8, (ILINE_SIZE*0)(CURRENT_ADDR) cache 0x8, (ILINE_SIZE*1)(CURRENT_ADDR) cache 0x8, (ILINE_SIZE*-4)(CURRENT_ADDR) cache 0x8, (ILINE_SIZE*-3)(CURRENT_ADDR) cache 0x8, (ILINE_SIZE*2)(CURRENT_ADDR) cache 0x8, (ILINE_SIZE*3)(CURRENT_ADDR) addu CURRENT_ADDR, BYTES_PER_LOOP // Get next starting line address bge END_ADDR, CURRENT_ADDR, next_icache_tag // Done yet? done_icache: jalr zero, ra END(init_icache) /************************************************************************************** * init_dcache invalidates all data cache entries **************************************************************************************/ LEAF(init_dcache) // Can be skipped if Config7[HCI] set mfc0 TEMP1, C0_CONFIG, 7 // Read CP0 Config7 ext TEMP1, TEMP1, HCI, 1 // extract HCI bne TEMP1, zero, done_dcache mfc0 CONFIG_1, C0_CONFIG1 // read C0_Config1 // Isolate D$ Line Size ext LINE_SIZE, CONFIG_1, CFG1_DLSHIFT, 3 // extract DL // Skip ahead if No D$ beq LINE_SIZE, zero, done_dcache li TEMP1, 2 sllv LINE_SIZE, TEMP1, LINE_SIZE // Now have true D$ line size in bytes ext SET_SIZE, CONFIG_1, CFG1_DSSHIFT, 3 // extract DS li TEMP1, 64 sllv SET_SIZE, TEMP1, SET_SIZE // D$ Sets per way // Config1DA == D$ Assoc - 1 ext ASSOC, CONFIG_1, CFG1_DASHIFT, 3 // extract DA addiu ASSOC, 1 li TEMP1, (LINES_PER_ITER) mul SET_SIZE, SET_SIZE, ASSOC // Total number of sets mul TOTAL_BYTES, SET_SIZE, LINE_SIZE // Total number of bytes mul BYTES_PER_LOOP, LINE_SIZE, TEMP1 // Total bytes per loop // Set the starting address at the beginning of kgeg0 (0x80000000) which will corresponds to // way 0 index 0 of the cache and position so starting address is in the // middle of the first bytes per loop because the code will use + and - offsets lui CURRENT_ADDR, 0x8000 srl TEMP1, BYTES_PER_LOOP, 1 addu CURRENT_ADDR, TEMP1, CURRENT_ADDR addu END_ADDR, CURRENT_ADDR, TOTAL_BYTES // make ending address subu END_ADDR, END_ADDR, BYTES_PER_LOOP // -1 // Clear TagLo/TagHi registers mtc0 zero, C0_TAGLO, 2 // write C0_DTagLo mtc0 zero, C0_TAGHI, 2 // Note: not all implementations will have a tag Hi but writes will be ignored if not present ehb // due to offset field restrictions code assumes line size will not be more that 128 bytes for a r5 or less core // or not more than 64 bytes for a r6 and greater core next_dcache_tag: // Index Store Tag Cache Op // Will invalidate the tag entry, clear the lock bit, and clear the LRF bit cache 0x9, (DLINE_SIZE*-2)(CURRENT_ADDR) cache 0x9, (DLINE_SIZE*-1)(CURRENT_ADDR) cache 0x9, (DLINE_SIZE*0)(CURRENT_ADDR) cache 0x9, (DLINE_SIZE*1)(CURRENT_ADDR) cache 0x9, (DLINE_SIZE*-4)(CURRENT_ADDR) cache 0x9, (DLINE_SIZE*-3)(CURRENT_ADDR) cache 0x9, (DLINE_SIZE*2)(CURRENT_ADDR) cache 0x9, (DLINE_SIZE*3)(CURRENT_ADDR) addu CURRENT_ADDR, BYTES_PER_LOOP // Get next starting line address bge END_ADDR, CURRENT_ADDR, next_dcache_tag // Done yet? done_dcache: jalr zero, ra END(init_dcache) LEAF(change_k0_cca) // NOTE! This code must be executed in KSEG1 (not KSGE0 uncached) // Set CCA for kseg0 to cacheable mfc0 TEMP1, C0_CONFIG // read C0_Config li TEMP2, 3 // CCA for all others beqz r11_is_cps, set_kseg0_cca li TEMP2, 5 // CCA for coherent cores (fall through) set_kseg0_cca: ins TEMP1, TEMP2, 0, 3 // insert K0 mtc0 TEMP1, C0_CONFIG // write C0_Config jalr.hb zero, ra END(change_k0_cca) LEAF(flush_dcache) mfc0 CONFIG_1, C0_CONFIG1 // read C0_Config1 // Isolate D$ Line Size ext LINE_SIZE, CONFIG_1, CFG1_DLSHIFT, 3 // extract DL // Skip ahead if No D$ beq LINE_SIZE, zero, done_flush_dcache li TEMP1, 2 sllv LINE_SIZE, TEMP1, LINE_SIZE // Now have true D$ line size in bytes ext SET_SIZE, CONFIG_1, CFG1_DSSHIFT, 3 // extract DS li TEMP1, 64 sllv SET_SIZE, TEMP1, SET_SIZE // D$ Sets per way // Config1DA == D$ Assoc - 1 ext ASSOC, CONFIG_1, CFG1_DASHIFT, 3 // extract DA addiu ASSOC, 1 li TEMP1, (LINES_PER_ITER) mul SET_SIZE, SET_SIZE, ASSOC // Total number of sets mul TOTAL_BYTES, SET_SIZE, LINE_SIZE // Total number of bytes mul BYTES_PER_LOOP, LINE_SIZE, TEMP1 // Total bytes per loop lui CURRENT_ADDR, 0x8000 // Get a KSeg0 address for cacheops srl TEMP1, BYTES_PER_LOOP, 1 addu CURRENT_ADDR, TEMP1, CURRENT_ADDR addu END_ADDR, CURRENT_ADDR, TOTAL_BYTES // make ending address subu END_ADDR, END_ADDR, BYTES_PER_LOOP // -1 // Clear TagLo/TagHi registers mtc0 zero, C0_TAGLO, 2 // write C0_DTagLo mtc0 zero, C0_TAGHI, 2 // Note: not all implementations will have a tag Hi but writes will be ignored if not present ehb // due to offset field restrictions code assumes line size will not be more that 128 bytes for a r5 or less core // or not more than 64 bytes for a r6 and greater core fnext_dcache_tag: // Index writeback invalidate Cache Op // Will invalidate the tag entry, clear the lock bit, and clear the LRF bit cache 0x1, (DLINE_SIZE*-2)(CURRENT_ADDR) cache 0x1, (DLINE_SIZE*-1)(CURRENT_ADDR) cache 0x1, (DLINE_SIZE*0)(CURRENT_ADDR) cache 0x1, (DLINE_SIZE*1)(CURRENT_ADDR) cache 0x1, (DLINE_SIZE*-4)(CURRENT_ADDR) cache 0x1, (DLINE_SIZE*-3)(CURRENT_ADDR) cache 0x1, (DLINE_SIZE*2)(CURRENT_ADDR) cache 0x1, (DLINE_SIZE*3)(CURRENT_ADDR) addu CURRENT_ADDR, BYTES_PER_LOOP // Get next starting line address bge END_ADDR, CURRENT_ADDR, fnext_dcache_tag // Done yet? done_flush_dcache: sync jalr zero, ra END(flush_dcache) #undef LINE_SIZE #undef BYTES_PER_LOOP #undef SET_SIZE #undef ASSOC #undef CONFIG_1 #undef END_ADDR #undef TOTAL_BYTES #undef CURRENT_ADDR #undef TEMP1 #undef TEMP2