#if defined(JAZZ) /*++ Copyright (c) 1991 Microsoft Corporation Module Name: memtest.s Abstract: This module contains the assembly routine to test memory. Author: Lluis Abello (lluis) 10-Aug-91 Environment: Executes in kernal mode. --*/ #include "ksmips.h" #include "selfmap.h" #include "j4reset.h" .text .set noreorder .set noat /*++ VOID WriteMemoryAddressTest( StartAddress Size Xor pattern ) Routine Description: This routine will store the address of each location xored with the Pattern into each location. It packs together two words and does double word stores to speed it up. Arguments: a0 - supplies start of memory area to test (must be in KSEG0) a1 - supplies length of memory area in bytes a2 - supplies the pattern to Xor with. Note: the values of the arguments are preserved. Return Value: This routine returns no value. --*/ LEAF_ENTRY(WriteMemoryAddressTest) // add t1,a0,a1 // t1 = last address. // xor t0,a0,a2 // t0 value to write // move t2,a0 // t2=current address //writeaddress: // mtc1 t0,f0 // move lower word to cop1 // addiu t2,t2,4 // compute next address // xor t0,t2,a2 // next pattern // mtc1 t0,f1 // move upper word to cop1 // addiu t2,t2,4 // compute next address // sdc1 f0,-8(t2) // store even doubleword. // xor t0,t2,a2 // next pattern // mtc1 t0,f0 // move lower word to cop1 // addiu t2,t2,4 // compute next address // xor t0,t2,a2 // next pattern // mtc1 t0,f1 // move upper word to cop1 // addiu t2,t2,4 // compute next address // sdc1 f0,-8(t2) // store odd doubleword. // bne t2,t1, writeaddress // check for end condition // xor t0,t2,a2 // value to write // j ra // nop // // Enable parity exceptions. To make sure this works. // li t1,(1 << PSR_CU1) | (1 << PSR_BEV) mtc0 t1,psr nop nop // // Create dirty exclusive cache blocks and zero the data. // mfc0 t5,config // get configuration data li t4,16 // srl t0,t5,CONFIG_DB // compute data cache line size and t0,t0,1 // sll t4,t4,t0 // 1st fill size li t1,(1 << CONFIG_SC) and t0,t5,t1 beq t0,zero,SecondaryCache // if zero secondary cache PrimaryOnly: move t0,a0 // put start address in t0 addu t9,t0,a1 // compute ending address and t8,t4,0x10 // test if 16-byte cache block // // Store data using primary data cache only. // 30: cache CREATE_DIRTY_EXCLUSIVE_D,0(t0) // create cache block move t1,t0 // save beginning block address xor t5,t0,a2 // create pattern to write mtc1 t5,f0 // move to lower word of double word addiu t0,t0,4 // increment address xor t5,t0,a2 // create pattern to write mtc1 t5,f1 // move to upper word of double word addiu t0,t0,4 // increment address sdc1 f0,-8(t0) // store double word xor t5,t0,a2 // create pattern to write mtc1 t5,f0 // move to lower word of double word addiu t0,t0,4 // increment address xor t5,t0,a2 // create pattern to write mtc1 t5,f1 // move to upper word of double word addiu t0,t0,4 // increment address bne zero,t8,40f // if ne, 16-byte cache line sdc1 f0,-8(t0) // store double word xor t5,t0,a2 // create pattern to write mtc1 t5,f0 // move to lower word of double word addiu t0,t0,4 // increment address xor t5,t0,a2 // create pattern to write mtc1 t5,f1 // move to upper word of double word addiu t0,t0,4 // increment address sdc1 f0,-8(t0) // store double word xor t5,t0,a2 // create pattern to write mtc1 t5,f0 // move to lower word of double word addiu t0,t0,4 // increment address xor t5,t0,a2 // create pattern to write mtc1 t5,f1 // move to upper word of double word addiu t0,t0,4 // increment address sdc1 f0,-8(t0) // store double word 40: nop nop cache INDEX_WRITEBACK_INVALIDATE_D,(t1) // Flush out the data nop bne t0,t9,30b // if ne, more blocks to zero nop j ra nop // // Store data using primary and secondary data caches. // SecondaryCache: // t4 = primary data cache line size srl t0,t5,CONFIG_DC // compute primary data cache size and t0,t0,0x7 // addu t0,t0,12 // li t6,1 // sll t6,t6,t0 // t6 = primary data cache size srl t0,t5,CONFIG_SB // compute secondary cache line size and t0,t0,3 // li t8,16 // sll t8,t8,t0 // t8 = secondary cache line size li t5,SECONDARY_CACHE_SIZE // t5 = secondary cache size // // Write Back all the dirty data from the primary to the secondary cache. // li t1,KSEG0_BASE+(1<<20) // get virtual address to index cache addu t2,t1,t6 // add cache size subu t2,t2,t4 // adjust for cache line size. WriteBackPrimary: cache INDEX_WRITEBACK_INVALIDATE_D,0(t1) // Invalidate Data cache bne t1,t2,WriteBackPrimary // loop addu t1,t1,t4 // increment index by cache line // // Write Back all the dirty data from the secondary to memory // li t1,KSEG0_BASE+(1<<20) // get virtual address to index cache addu t2,t1,t5 // add cache size subu t2,t2,t8 // adjust for cache line size. WriteBackSecondary: cache INDEX_WRITEBACK_INVALIDATE_SD,0(t1) // Invalidate Data cache bne t1,t2,WriteBackSecondary// loop addu t1,t1,t8 // increment index by cache line // // Now all the dirty data has been saved. And both primary and secondary // Data caches are invalid an clean. // move t0,a0 // put start address in t0 addu t9,t0,a1 // compute ending address li t1,16 // If the secondary line is 16 beq t1,t8,Secondary16 // bytes go do the write li t1,32 // If the secondary line is 32 beq t1,t8,Secondary32 // bytes go do the write nop .globl Secondary64 .align 4 mtc0 zero,taghi Secondary64: srl t5,t0,5 andi t5,t5,0x380 ori t5,(5 << TAGLO_SSTATE) li t2,~KSEG1_BASE and t2,t2,t0 srl t2,t2,17 sll t2,t2,13 or t2,t5,t2 mtc0 t2,taglo nop nop cache INDEX_STORE_TAG_SD,0(t0)// create cache block xor t5,t0,a2 // create pattern to write sw t5,0(t0) // store word addiu t0,t0,4 // increment address xor t5,t0,a2 // create pattern to write sw t5,0(t0) // store word addiu t0,t0,4 // increment address xor t5,t0,a2 // create pattern to write sw t5,0(t0) // store word addiu t0,t0,4 // increment address xor t5,t0,a2 // create pattern to write sw t5,0(t0) // store word addiu t0,t0,4 // increment address xor t5,t0,a2 // create pattern to write sw t5,0(t0) // store word addiu t0,t0,4 // increment address xor t5,t0,a2 // create pattern to write sw t5,0(t0) // store word addiu t0,t0,4 // increment address xor t5,t0,a2 // create pattern to write sw t5,0(t0) // store word addiu t0,t0,4 // increment address xor t5,t0,a2 // create pattern to write sw t5,0(t0) // store word addiu t0,t0,4 // increment address xor t5,t0,a2 // create pattern to write sw t5,0(t0) // store word addiu t0,t0,4 // increment address xor t5,t0,a2 // create pattern to write sw t5,0(t0) // store word addiu t0,t0,4 // increment address xor t5,t0,a2 // create pattern to write sw t5,0(t0) // store word addiu t0,t0,4 // increment address xor t5,t0,a2 // create pattern to write sw t5,0(t0) // store word addiu t0,t0,4 // increment address xor t5,t0,a2 // create pattern to write sw t5,0(t0) // store word addiu t0,t0,4 // increment address xor t5,t0,a2 // create pattern to write sw t5,0(t0) // store word addiu t0,t0,4 // increment address xor t5,t0,a2 // create pattern to write sw t5,0(t0) // store word addiu t0,t0,4 // increment address xor t5,t0,a2 // create pattern to write sw t5,0(t0) // store word addiu t0,t0,4 // increment address nop cache HIT_WRITEBACK_INVALIDATE_SD,-64(t0) // Flush cache block bne t0,t9,Secondary64 // if ne, more data to zero nop j ra nop Secondary16: cache CREATE_DIRTY_EXCLUSIVE_SD,0(t0) // create cache block xor t5,t0,a2 // create pattern to write sw t5,0(t0) // store word addiu t0,t0,4 // increment address xor t5,t0,a2 // create pattern to write sw t5,0(t0) // store word addiu t0,t0,4 // increment address xor t5,t0,a2 // create pattern to write sw t5,0(t0) // store word addiu t0,t0,4 // increment address xor t5,t0,a2 // create pattern to write sw t5,0(t0) // store word addiu t0,t0,4 // increment address nop cache HIT_WRITEBACK_INVALIDATE_SD,-16(t0) // Flush cache block bne t0,t9,Secondary16 // if ne, more data to zero nop j ra nop Secondary32: cache CREATE_DIRTY_EXCLUSIVE_SD,0(t0) // create cache block xor t5,t0,a2 // create pattern to write sw t5,0(t0) // store word addiu t0,t0,4 // increment address xor t5,t0,a2 // create pattern to write sw t5,0(t0) // store word addiu t0,t0,4 // increment address xor t5,t0,a2 // create pattern to write sw t5,0(t0) // store word addiu t0,t0,4 // increment address xor t5,t0,a2 // create pattern to write sw t5,0(t0) // store word addiu t0,t0,4 // increment address xor t5,t0,a2 // create pattern to write sw t5,0(t0) // store word addiu t0,t0,4 // increment address xor t5,t0,a2 // create pattern to write sw t5,0(t0) // store word addiu t0,t0,4 // increment address xor t5,t0,a2 // create pattern to write sw t5,0(t0) // store word addiu t0,t0,4 // increment address xor t5,t0,a2 // create pattern to write sw t5,0(t0) // store word addiu t0,t0,4 // increment address nop cache HIT_WRITEBACK_INVALIDATE_SD,-32(t0) // Flush cache block bne t0,t9,Secondary32 // if ne, more data to zero nop j ra nop .end WriteMemoryAddressTest /*++ VOID CheckMemoryAddressTest( StartAddress Size Xor pattern LedDisplayValue ) Routine Description: This routine will check that each location contains it's address xored with the Pattern as written by WriteMemoryAddressTest. Note: the values of the arguments are preserved. Arguments: This routine will check that each location contains it's address xored with the Pattern as written by WriteMemoryAddressTest. The memory is read cached or non cached according to the address specified by a0. Write address test writes allways KSEG1_ADR=KSEG1_ADR ^ KSEG1_XOR if a0 is in KSEG0 to read the data cached, then the XOR_PATTERN Must be such that: KSEG0_ADR ^ KSEG0_XOR = KSEG1_ADR ^ KSEG1_XOR Examples: If XorPattern with which WriteMemoryAddressTest was called is KSEG1_PAT and the XorPattern this routine needs is KSEG0_PAT: KSEG1_XOR Written KSEG0_XOR So that 0x00000000 0xA0 0x20000000 0x80 ^ 0x20 = 0xA0 0xFFFFFFFF 0x5F 0xDFFFFFFF 0x80 ^ 0xDF = 0x5F 0x01010101 0xA1 0x21010101 0x80 ^ 0x21 = 0xA1 Note: the values of the arguments are preserved. a0 - supplies start of memory area to test a1 - supplies length of memory area in bytes a2 - supplies the pattern to Xor with. a3 - suplies the value to display in the led in case of failure Return Value: If successful returns a 0, otherwise returns a 1. --*/ LEAF_ENTRY(CheckMemoryAddressTest) move t3,a0 // t3 first address. add t2,t3,a1 // last address. checkaddress: lw t1,0(t3) // load from first location xor t0,t3,a2 // first expected value bne t1,t0,PatternFail addiu t3,t3,4 // compute next address lw t1,0(t3) // load from first location xor t0,t3,a2 // first expected value bne t1,t0,PatternFail addiu t3,t3,4 // compute next address lw t1,0(t3) // load from first location xor t0,t3,a2 // first expected value bne t1,t0,PatternFail addiu t3,t3,4 // compute next address lw t1,0(t3) // load from first location xor t0,t3,a2 // first expected value bne t1,t0,PatternFail // check last one. addiu t3,t3,4 // compute next address bne t3,t2, checkaddress // check for end condition nop j ra // return a zero to the caller move v0,zero // set return value to zero. PatternFail: j ra // // addiu v0,zero,1 // return a 1 to the caller addu v0,zero,t3 // return failing address to caller .end CheckMemoryAddressTest /*++ VOID WriteVideoMemoryAddressTest( StartAddress Size ) Routine Description: This routine will store the address of each location into each location. It packs two double words together to do sdc1 and speed it up. Arguments: a0 - supplies start of memory area to test a1 - supplies length of memory area in bytes Note: the values of the arguments are preserved. Return Value: This routine returns no value. --*/ LEAF_ENTRY(WriteVideoMemoryAddressTest) addu t1,a0,a1 // t1 = last address. move t2,a0 // t2=current address 10: mtc1 t2,f0 // move lower word to cop1 addiu t2,t2,4 // compute next address mtc1 t2,f1 // move upper word to cop1 addiu t2,t2,4 // compute next address sdc1 f0,-8(t2) // store even doubleword mtc1 t2,f2 // move lower word to cop1 addiu t2,t2,4 // compute next address mtc1 t2,f3 // move upper word to cop1 addiu t2,t2,4 // compute next address bne t2,t1, 10b // check for end condition sdc1 f2,-8(t2) // store odd doubleword. j ra nop .end WriteVideoMemoryAddressTest /*++ VOID CheckVideoMemoryAddressTest( StartAddress Size ) Routine Description: This routine will check that each location contains it's address xored with the Pattern as written by WriteMemoryAddressTest. Arguments: Note: the values of the arguments are preserved. a0 - supplies start of memory area to test a1 - supplies length of memory area in bytes Return Value: This routine returns FALSE if no errors are found. Otherwise returns true. --*/ LEAF_ENTRY(CheckVideoMemoryAddressTest) addu t2,a0,a1 // compute last address. 10: ldc1 f0,0(a0) // read data ldc1 f2,8(a0) // read data mfc1 t0,f0 // move from cop mfc1 t1,f1 // move from cop bne t0,a0,VideoMemoryFail // compare addiu a0,a0,4 // inc address for next expected value bne t1,a0,VideoMemoryFail // compare. mfc1 t0,f2 // move from cop mfc1 t1,f3 // move from cop addiu a0,a0,4 // inc address for next expected value bne t0,a0,VideoMemoryFail // compare addiu a0,a0,4 // inc address for next expected value bne t1,a0,VideoMemoryFail // compare. addiu a0,a0,4 bne a0,t2,10b nop j ra // return a zero to the caller move v0,zero // VideoMemoryFail: j ra // addiu v0,zero,1 // return a 1 to the caller .end CheckVideoMemoryAddressTest .set at LEAF_ENTRY(RomReadMergeWrite) mfc0 t5,config // read config lui t0,0xa004 // uncached address lui t1,0x8004 //8004 // same cached address R4KFIX li t6,16 // end of loop counter move t2,zero // byte counter srl t3,t5,CONFIG_DC // compute data cache size and t3,t3,0x7 // addu t3,t3,12 // li t9,1 // sll t9,t9,t3 // t9 = data cache size WriteNextByte: sw zero,0(t1) // clear memory line sw zero,4(t1) // clear memory line sw zero,8(t1) // clear memory line sw zero,12(t1) // clear memory line addu t8,t9,t1 // add cache size to address lw zero,0(t8) // Force a replacement of the cache line -> updates memory add t4,t0,t2 // compute ith byte address nor t5,t2,zero // invert value sb t5,0(t4) // write byte <= read/merge/write move t3,zero // init read index CheckNextByte: add t4,t3,t1 // compute cached address lb t4,0(t4) // read byte beq t3,t2, Inverted // if equal is the inverted value nor t5,t2,zero move t5,zero // else expect a zero Inverted: bne t4,t5, Error // compare with what we wrote. addiu t3,t3,1 // next byte index bne t3,t6,CheckNextByte nop addiu t2,t2,1 // inc write index bne t2,t6,WriteNextByte nop // do the same storing half words move t2,zero // byte counter WriteNextHalf: sw zero,0(t1) // clear memory line sw zero,4(t1) // clear memory line sw zero,8(t1) // clear memory line sw zero,12(t1) // clear memory line addu t8,t9,t1 // add cache size to address lw zero,0(t8) // Force a replacement of the cache line -> updates memory add t4,t0,t2 // compute ith byte address nor t5,t2,zero // invert value sh t5,0(t4) // write half <= read/merge/write move t3,zero // init read index CheckNextHalf: add t4,t3,t1 // compute cached address lh t4,0(t4) // read half beq t3,t2,InvertedHalf // if equal is the inverted value nor t5,t2,zero // invert value move t5,zero // else expect a zero InvertedHalf: bne t4,t5, Error // compare with what we wrote. addiu t3,t3,2 // next half index bne t3,t6,CheckNextHalf nop addiu t2,t2,2 // inc write index bne t2,t6,WriteNextHalf nop j ra move v0,zero // return no errors Error: sw t4,20(t0) j ra addiu v0,zero,1 // return errors .end RomReadMergeWrite .set noat /*++ VOID FillVideoMemory( StartAddress Size Pattern ) Routine Description: This routine will fill the given range of video memory with the supplied pattern. The fill is done by doing double word writes and the range must be 16byte aligned. Arguments: a0 - supplies start of memory area a1 - supplies length of memory area a2 - supplies the pattern to fill video memory with. (1byte) Return Value: None. --*/ LEAF_ENTRY(FillVideoMemory) andi a2,a2,0xFF // Mask out byte sll t0,a2,8 // Shift Byte or t0,t0,a2 // or them to make half sll a2,t0,16 // shift half or a2,t0,a2 // or them to make a word addu t0,a0,a1 // compute last address. mtc1 a2,f0 // move pattern to cop1 mtc1 a2,f1 // move pattern to cop1 10: addiu a0,a0,16 // compute next address sdc1 f0,-16(a0) // do a store bne a0,t0,10b // check for end condition sdc1 f0,-8(a0) // do a store j ra nop .end FillVideoMemory /*++ VOID FwVideoScroll( PUCHAR StartAddress, PUCHAR EndAddress, PUCHAR Destination ); Routine Description: This routine writes the pattern to the specified range of addresses doing video pipeline writes on double writes. Arguments: StartAddress - Suplies the range of addresses to be scrolled EndAddress - this addresses must be aligned to 256byte boundaries. Destination - Suplies the Destination address for the scroll (i.e the contents of StartAddress will be moved to destination address and so on). Return Value: None. --*/ .set noreorder .set noat LEAF_ENTRY(FwVideoScroll) ScrollRead: ldc1 f0,0x0(a0) // read video ldc1 f2,0x8(a0) ldc1 f4,0x10(a0) ldc1 f6,0x18(a0) ldc1 f8,0x20(a0) ldc1 f10,0x28(a0) ldc1 f12,0x30(a0) ldc1 f14,0x38(a0) ldc1 f16,0x40(a0) ldc1 f18,0x48(a0) ldc1 f20,0x50(a0) ldc1 f22,0x58(a0) ldc1 f24,0x60(a0) ldc1 f26,0x68(a0) ldc1 f28,0x70(a0) ldc1 f30,0x78(a0) addiu a0,a0,0x80 // increment source address sdc1 f0,0x0(a2) // store them pipelining sdc1 f2,0x8(a2) sdc1 f4,0x10(a2) sdc1 f6,0x18(a2) sdc1 f8,0x20(a2) sdc1 f10,0x28(a2) sdc1 f12,0x30(a2) sdc1 f14,0x38(a2) sdc1 f16,0x40(a2) sdc1 f18,0x48(a2) sdc1 f20,0x50(a2) sdc1 f22,0x58(a2) sdc1 f24,0x60(a2) sdc1 f26,0x68(a2) sdc1 f28,0x70(a2) sdc1 f30,0x78(a2) bne a0,a1,ScrollRead // check for last addiu a2,a2,0x80 // increment destination j ra // return to caller nop .end FwVideoScroll /*++ VOID StoreDoubleWord( IN ULONG Address, IN PVOID Value ); Routine Description: This routine writes the value pointed by a1 to the address supplied in a0. Arguments: a0 - Address to write double to. a1 - pointer to value to write. Return Value: None. --*/ LEAF_ENTRY(StoreDoubleWord) ldc1 f0,0(a1) nop sdc1 f0,0(a0) j ra nop .end StoreDoubleWord /*++ VOID LoadDoubleWord( IN ULONG Address, OUT PVOID Result ); Routine Description: This routine reads a double from the address suplied in a0 and stores the red value in the address supplied by result. Arguments: a0 - Address to read double from. a1 - pointer to double to store result. Return Value: None. --*/ LEAF_ENTRY(LoadDoubleWord) ldc1 f0,0(a0) nop sdc1 f0,0(a1) j ra nop .end /*++ VOID WildZeroMemory( IN ULONG StartAddress, IN ULONG Size ) Routine Description: This routine zeroes the specified range of memory by doing cache line writes. Arguments: a0 - supplies the physical address of the range of memory to zero. This address must be a multiple of the Data Cache Size. a1 - supplies length of memory to zero. This value must be a multiple of the Data Cache Size. Return Value: None. --*/ LEAF_ENTRY(WildZeroMemory) // TEMPTEMP // li t0,KSEG1_BASE // get non-cached base // or t0,t0,a0 // physical address in KSEG1 // addu t1,t0,a1 // end // mtc1 zero,f0 // set write pattern // mtc1 zero,f1 // // //10: // sdc1 f0,0(t0) // addu t0,t0,16 // bne t0,t1,10b // sdc1 f0,-8(t0) // // li t0,KSEG0_BASE // get cached base // or t0,t0,a0 // physical address in KSEG0 // addu t1,t0,a1 // end //10: // lw zero,0(t0) // addu t0,t0,16 // bne t0,t1,10b // nop // // j ra // nop // TEMPTEMP // // Create dirty exclusive cache blocks and zero the data. // mfc0 t5,config // get configuration data li t4,16 // srl t0,t5,CONFIG_DB // compute data cache line size and t0,t0,1 // sll t4,t4,t0 // t4 = 1st fill size li t1,(1 << CONFIG_SC) and t0,t5,t1 mtc1 zero,f0 // set write pattern mtc1 zero,f1 // beq t0,zero,SecondaryWild // if zero secondary cache PrimaryWild: li t0,KSEG0_BASE // get cached base or t0,t0,a0 // physical address in KSEG0 addu t9,t0,a1 // compute ending address and t8,t4,0x10 // test if 16-byte cache block // // Zero data using primary data cache only. // 30: cache CREATE_DIRTY_EXCLUSIVE_D,0(t0) // create cache block move t1,t0 // save beginning block address addu t0,t0,t4 // compute next block address bne zero,t8,40f // if ne, 16-byte cache line sdc1 f0,-16(t0) // sdc1 f0,-24(t0) // zero 16 bytes sdc1 f0,-32(t0) // 40: sdc1 f0,-8(t0) // zero 16 bytes nop nop cache INDEX_WRITEBACK_INVALIDATE_D,0(t1) // Flush out the data bne t0,t9,30b // if ne, more blocks to zero nop j ra nop // // Zero data using primary and secondary data caches. // SecondaryWild: // t4 = primary data cache line size srl t0,t5,CONFIG_DC // compute primary data cache size and t0,t0,0x7 // addu t0,t0,12 // li t6,1 // sll t6,t6,t0 // t6 = primary data cache size srl t0,t5,CONFIG_SB // compute secondary cache line size and t0,t0,3 // li t8,16 // sll t8,t8,t0 // t8 = secondary cache line size li t5,SECONDARY_CACHE_SIZE // t5 = secondary cache size // // Write Back all the dirty data from the primary to the secondary cache. // li t1,KSEG0_BASE+(1<<20) // get virtual address to index cache addu t2,t1,t6 // add cache size subu t2,t2,t4 // adjust for cache line size. WriteBackPrimaryW: cache INDEX_WRITEBACK_INVALIDATE_D,0(t1) // Invalidate Data cache bne t1,t2,WriteBackPrimaryW // loop addu t1,t1,t4 // increment index by cache line // // Write Back all the dirty data from the secondary to memory // li t1,KSEG0_BASE+(1<<20) // get virtual address to index cache addu t2,t1,t5 // add cache size subu t2,t2,t8 // adjust for cache line size. WriteBackSecondaryW: cache INDEX_WRITEBACK_INVALIDATE_SD,0(t1) // Invalidate Data cache bne t1,t2,WriteBackSecondaryW // loop addu t1,t1,t8 // increment index by cache line // // Now all the dirty data has been saved. And both primary and secondary // Data caches are invalid an clean. // li t0,KSEG0_BASE // get cached base or t0,t0,a0 // physical address in KSEG0 addu t9,t0,a1 // compute ending address subu t9,t9,t8 // adjust last address li t1,16 // If the secondary line is 16 beq t1,t8,SecondaryW16 // bytes go do the write li t1,32 // If the secondary line is 32 beq t1,t8,SecondaryW32 // bytes go do the write nop SecondaryW64: cache CREATE_DIRTY_EXCLUSIVE_SD,0(t0) // create cache block sdc1 f0,0(t0) // store double word sdc1 f0,8(t0) // store double word sdc1 f0,16(t0) // store double word sdc1 f0,24(t0) // store double word sdc1 f0,32(t0) // store double word sdc1 f0,40(t0) // store double word sdc1 f0,48(t0) // store double word sdc1 f0,56(t0) // store double word cache HIT_WRITEBACK_INVALIDATE_SD,0(t0) // Flush cache block bne t0,t9,SecondaryW64 // if ne, more data to zero addiu t0,t0,64 j ra nop SecondaryW32: cache CREATE_DIRTY_EXCLUSIVE_SD,0(t0) // create cache block sdc1 f0,0(t0) // store double word sdc1 f0,8(t0) // store double word sdc1 f0,16(t0) // store double word sdc1 f0,24(t0) // store double word cache HIT_WRITEBACK_INVALIDATE_SD,0(t0) // Flush cache block bne t0,t9,SecondaryW32 // if ne, more data to zero addiu t0,t0,32 j ra nop SecondaryW16: cache CREATE_DIRTY_EXCLUSIVE_SD,0(t0) // create cache block sdc1 f0,0(t0) // store double word sdc1 f0,8(t0) // store double word cache HIT_WRITEBACK_INVALIDATE_SD,0(t0) // Flush cache block bne t0,t9,SecondaryW16 // if ne, more data to zero addiu t0,t0,16 j ra nop .end WildZeroMemory #endif