#if defined(JAZZ) && defined(R4000) // TITLE("Interrupt and Exception Processing") //++ // // Copyright (c) 1991 Microsoft Corporation // // Module Name: // // j4trap.s // // Abstract: // // This module implements the code necessary to field and process MIPS // interrupt and exception conditions during bootstrap. // // Author: // // David N. Cutler (davec) 21-Apr-1991 // // Environment: // // Kernel mode only. // // Revision History: // //-- #include "ksmips.h" SBTTL("Constant Value Definitions") //++ // // The following are definitions of constants used in this module. // //-- #define PSR_MASK (~((0x3 << PSR_KSU) | (1 << PSR_EXL))) // PSR exception mask //++ // // Define dummy data allocation. // //-- .data .space 4 // SavedK1Address: .space 4 // address where to save k1 to return to fw. SBTTL("General Exception Vector Routine") //++ // // Routine Description: // // This routine is entered as the result of a general exception. The reason // for the exception is contained in the cause register. When this routine // is entered, interrupts are disabled. // // All exception that occur during the bootstrap process are treated as // if a breakpoint had occurred. This ultimately causes either the kernel // debugger or a stub routine provided by the bootstrap itself to be // invoked. // // The address of this routine is copied to the GEV in the SPB // so that the firmware jumps to this routine when a GeneralException // occurres. This routine must return to the address pointed by k1. // and leave the address where the firmware must return from the // exception in k0. // // // // Arguments: // // None. // // Return Value: // // None. // //-- LEAF_ENTRY(KiGeneralException) // // No TLB Miss is supposed to occurr during the boot process // The TbMiss handler is just the same general exception handler. // ALTERNATE_ENTRY(KiTbMiss) START_REGION(KiGeneralExceptionStartAddress) .set noreorder .set noat la k0,10f // transfer immediately to physical j k0 // nop // 10: subu k0,sp,TrapFrameLength // allocate trap frame sw sp,TrIntSp(k0) // save integer register sp move sp,k0 // set new stack pointer la k0,SavedK1Address // get address of where to save k1 sw k1,0(k0) // save firmware return address sw gp,TrIntGp(sp) // save integer register gp sw s8,TrIntS8(sp) // save integer register s8 sw ra,TrIntRa(sp) // save integer register ra mfc0 s8,cause // get cause of exception mfc0 k0,psr // get current processor status mfc0 k1,epc // get exception PC sw k0,TrPsr(sp) // save current PSR sw k1,TrFir(sp) // save exception PC bgez s8,20f // if gez, exception not in delay slot move s8,sp // set address of trap frame addu k1,k1,4 // compute address of exception 20: j KiBreakpointException // finish in breakpoint code nop // fill delay slot .set at .set reorder END_REGION(KiGeneralExceptionEndAddress) .end KiGeneralException SBTTL("Breakpoint Dispatch") //++ // // Routine Description: // // The following code is never executed. Its purpose is to allow the // kernel debugger to walk call frames backwards through an exception, // to support unwinding through exceptions for system services, and to // support get/set user context. // //-- NESTED_ENTRY(KiBreakpointDispatch, TrapFrameLength, zero); .set noreorder .set noat sw sp,TrIntSp(sp) // save stack pointer sw ra,TrIntRa(sp) // save return address sw ra,TrFir(sp) // save return address sw s8,TrIntS8(sp) // save frame pointer sw gp,TrIntGp(sp) // save general pointer move s8,sp // set frame pointer .set at .set reorder PROLOGUE_END //++ // // Routine Description: // // Control reaches here when a breakpoint exception code is read from the // cause register. When this routine is entered, interrupts are disabled. // // The function of this routine is to raise a breakpoint exception. // // N.B. Integer register v1 is not usuable in the first instuction of the // routine. // // Arguments: // // k0 - Supplies the current PSR with the EXL bit set. // k1 - Supplies the address of the faulting instruction. // gp - Supplies a pointer to the system short data area. // s8 - Supplies a pointer to the trap frame. // // Return Value: // // None. // //-- ALTERNATE_ENTRY(KiBreakpointException) GENERATE_TRAP_FRAME // save volatile machine state addu a0,s8,TrExceptionRecord // compute exception record address sw k1,ErExceptionAddress(a0) // save address of exception lw t0,0(k1) // get actual breakpoint instruction .set noreorder .set noat mfc0 k0,cause // get cause of exception .set at .set reorder li t1,XCODE_BREAKPOINT // get exception code for breakpoint li t2,STATUS_BREAKPOINT // set exception status code and k0,k0,R4000_XCODE_MASK // isolate exception code beq k0,t1,10f // if eq, breakpoint move t2,k0 // set status to cause value 10: sw t0,ErExceptionInformation(a0) // save breakpoint instruction sw t2,ErExceptionCode(a0) // sw zero,ErExceptionFlags(a0) // set exception flags sw zero,ErExceptionRecord(a0) // set associated record sw zero,ErNumberParameters(a0) // set number of parameters jal KiExceptionDispatch // join common code b 10b // dummy .end KiBreakpointDispatch SBTTL("Exception Dispatch") //++ // // Routine Desription: // // Control is transfered to this routine to call the exception // dispatcher to resolve an exception. // // Arguments: // // a0 - Supplies a pointer to an exception record. // // s8 - Supplies a pointer to a trap frame. // // Return Value: // // There is no return from this routine. // //-- NESTED_ENTRY(KiExceptionDispatch, ExceptionFrameLength, zero) subu sp,sp,ExceptionFrameLength // allocate exception frame sw ra,ExIntRa(sp) // save return address sw s0,ExIntS0(sp) // save integer registers s0 - s7 sw s1,ExIntS1(sp) // sw s2,ExIntS2(sp) // sw s3,ExIntS3(sp) // sw s4,ExIntS4(sp) // sw s5,ExIntS5(sp) // sw s6,ExIntS6(sp) // sw s7,ExIntS7(sp) // sdc1 f20,ExFltF20(sp) // save floating registers f20 - f31 sdc1 f22,ExFltF22(sp) // sdc1 f24,ExFltF24(sp) // sdc1 f26,ExFltF26(sp) // sdc1 f28,ExFltF28(sp) // sdc1 f30,ExFltF30(sp) // PROLOGUE_END // // Call the exception dispatcher. // move a1,sp // set exception frame address move a2,s8 // set trap frame address move a3,zero // set previous processor mode li t0,TRUE // set first chance TRUE sw t0,ExArgs + (4 * 4)(sp) // jal KiDispatchException // call exception dispatcher // // Restore the nonvolatile registers. // lw s0,ExIntS0(sp) // restore integer registers s0 - s7 lw s1,ExIntS1(sp) // lw s2,ExIntS2(sp) // lw s3,ExIntS3(sp) // lw s4,ExIntS4(sp) // lw s5,ExIntS5(sp) // lw s6,ExIntS6(sp) // lw s7,ExIntS7(sp) // ldc1 f20,ExFltF20(sp) // restore floating registers f20 - f31 ldc1 f22,ExFltF22(sp) // ldc1 f24,ExFltF24(sp) // ldc1 f26,ExFltF26(sp) // ldc1 f28,ExFltF28(sp) // ldc1 f30,ExFltF30(sp) // // // Exit from the exception. // lw t0,TrPsr(s8) // get previous processor status lw gp,TrIntGp(s8) // restore integer register gp li t3,(1 << PSR_CU1) | (1 << PSR_EXL) // ****** r4000 errata .set noreorder .set noat mtc0 t3,psr // ****** r4000 errata nop // ****** r4000 errata nop // ****** r4000 errata nop // ****** r4000 errata mtc0 t0,psr // disable interrupts nop // ****** r4000 errata jal KiRestoreTrapFrame // restore volatile state lw AT,TrIntAt(s8) // restore integer register at move sp,s8 // trim stack to trap frame la k0,SavedK1Address // get address of where to save k1 lw k1,(k0) // save firmware return address lw k0,TrFir(sp) // get continuation address lw s8,TrIntS8(sp) // restore integer register s8 lw ra,TrIntRa(sp) // restore return address j k1 // return to firmware lw sp,TrIntSp(sp) // restore stack pointer .set at .set reorder .end KiExceptionDispatch SBTTL("Fill Fixed Translation Buffer Entry") //++ // // VOID // KeFillFixedEntryTb ( // IN HARDWARE_PTE Pte[], // IN PVOID Virtual, // IN ULONG Index // ) // // Routine Description: // // This function fills a fixed translation buffer entry. // // Arguments: // // Pte (a0) - Supplies a pointer to the page table entries that are to be // written into the TB. // // Virtual (a1) - Supplies the virtual address of the entry that is to // be filled in the translation buffer. // // Index (a2) - Supplies the index where the TB entry is to be written. // // Return Value: // // None. // //-- LEAF_ENTRY(KeFillFixedEntryTb) lw t0,0(a0) // get first PTE value lw t1,4(a0) // get second PTE value DISABLE_INTERRUPTS(t2) // disable interrupts .set noreorder .set noat mfc0 t3,entryhi // get current PID and VPN2 srl a1,a1,ENTRYHI_VPN2 // isolate VPN2 of virtual address sll a1,a1,ENTRYHI_VPN2 // and t3,t3,0xff << ENTRYHI_PID // isolate current PID or a1,t3,a1 // merge PID with VPN2 of virtual address mtc0 a1,entryhi // set VPN2 and PID for probe mtc0 t0,entrylo0 // set first PTE value mtc0 t1,entrylo1 // set second PTE value mtc0 a2,index // set TB entry index nop // 1 cycle hazzard tlbwi // overwrite indexed TB entry nop // 3 cycle hazzard .set at .set reorder ENABLE_INTERRUPTS(t2) // enable interrupts j ra // return .end KeFillFixedEntryTb SBTTL("Flush Entire Translation Buffer") //++ // // VOID // KiFlushEntireTb ( // ) // // Routine Description: // // This function flushes the random part of the translation buffer. // // Arguments: // // None. // // Return Value: // // None. // //-- LEAF_ENTRY(KiFlushEntireTb) b KiFlushRandomTb // execute common code .end KiFlushEntireTb SBTTL("Flush Fixed Translation Buffer Entries") //++ // // VOID // KiFlushFixedTb ( // ) // // Routine Description: // // This function is called to flush all the fixed entries from the // translation buffer. // // Arguments: // // None. // // Return Value: // // None. // //-- LEAF_ENTRY(KiFlushFixedTb) li t0,FIXED_BASE // set base index of fixed TB entries li t3,FIXED_ENTRIES // set number of fixed TB entries b KiFlushTb // .end KiFlushFixedTb SBTTL("Flush Random Translation Buffer Entries") //++ // // VOID // KiFlushRandomTb ( // ) // // Routine Description: // // This function is called to flush all the random entries from the TB. // // Arguments: // // None. // // Return Value: // // None. // //-- LEAF_ENTRY(KiFlushRandomTb) li t0,FIXED_ENTRIES // set base index of random TB entries li t3,(48 - FIXED_ENTRIES) // set number of random TB entries ALTERNATE_ENTRY(KiFlushTb) li t4,KSEG0_BASE // set high part of TB entry DISABLE_INTERRUPTS(t2) // disable interrupts .set noreorder .set noat addu t3,t0,t3 // set index of highest entry + 1 sll t0,t0,INDEX_INDEX // shift starting index into position sll t3,t3,INDEX_INDEX // shift ending index into position mfc0 t1,entryhi // save contents of entryhi mtc0 zero,entrylo0 // set low part of TB entry mtc0 zero,entrylo1 // mtc0 t4,entryhi // mtc0 t0,index // set TB entry index 10: addu t0,t0,1 // nop // ****** r4000 errata nop // ****** r4000 errata nop // ****** r4000 errata nop // ****** r4000 errata tlbwi // write TB entry bne t0,t3,10b // if ne, more entries to flush mtc0 t0,index // set TB entry index nop // ****** r4000 errata nop // ****** r4000 errata nop // ****** r4000 errata mtc0 t1,entryhi // restore contents of entryhi nop // ****** r4000 errata nop // ****** r4000 errata nop // ****** r4000 errata .set at .set reorder ENABLE_INTERRUPTS(t2) // enable interrupts j ra // return .end KiFlushRandomTb SBTTL("Flush Single Translation Buffer Entry") //++ // // VOID // KiFlushSingleTb ( // IN BOOLEAN Invalid, // IN PVOID Virtual // ) // // Routine Description: // // This function flushes a single entry from the translation buffer. // // Arguments: // // Invalid (a0) - Supplies a boolean variable that determines the reason // that the TB entry is being flushed. // // Virtual (a1) - Supplies the virtual address of the entry that is to // be flushed from the translation buffer. // // Return Value: // // None. // //-- LEAF_ENTRY(KiFlushSingleTb) DISABLE_INTERRUPTS(t0) // disable interrupts .set noreorder .set noat srl t1,a1,ENTRYHI_VPN2 // clear all but VPN2 of virtual address mfc0 t2,entryhi // get current PID and VPN2 sll t1,t1,ENTRYHI_VPN2 // and t2,t2,0xff << ENTRYHI_PID // isolate current PID or t1,t1,t2 // merge PID with VPN2 of virtual address mtc0 t1,entryhi // set VPN2 and PID for probe nop // 3 cycle hazzard nop // nop // nop // ****** r4000 errata nop // ****** r4000 errata tlbp // probe for entry in TB nop // 2 cycle hazzard nop // mfc0 t3,index // read result of probe nop // 1 cycle hazzard bltz t3,30f // if ltz, entry is not in TB sll t1,a1,0x1f - (ENTRYHI_VPN2 - 1) // shift low bit of VPN into sign bltzl t1,10f // if ltz, invalidate second PTE mtc0 zero,entrylo1 // clear second PTE for flush mtc0 zero,entrylo0 // clear first PTE for flush 10: nop // 1 cycle hazzard nop // ****** r4000 errata nop // ****** r4000 errata nop // ****** r4000 errata nop // ****** r4000 errata tlbwi // overwrite index TB entry nop // 3 cycle hazzard nop // ****** r4000 errata nop // ****** r4000 errata .set at .set reorder 30: ENABLE_INTERRUPTS(t0) // enable interrupts j ra // return .end KiFlushSingleTb SBTTL("Probe Tb Entry") //++ // // ULONG // KiProbeEntryTb ( // IN PVOID VirtualAddress // ) // // Routine Description: // // This function is called to determine if a specified entry is valid /// and within the fixed portion of the TB. // // Arguments: // // VirtualAddress - Supplies the virtual address to probe. // // Return Value: // // A value of TRUE is returned if the specified entry is valid and within // the fixed part of the TB. Otherwise, a value of FALSE is returned. // //-- LEAF_ENTRY(KiProbeEntryTb) DISABLE_INTERRUPTS(t0) // disable interrupts .set noreorder .set noat srl t1,a0,ENTRYHI_VPN2 // clear all but VPN2 of virtual address mfc0 t2,entryhi // get current PID and VPN2 sll t1,t1,ENTRYHI_VPN2 // and t2,t2,0xff << ENTRYHI_PID // isolate current PID or t1,t1,t2 // merge PID with VPN2 of virtual address mtc0 t1,entryhi // set VPN2 and PID for probe nop // 3 cycle hazzard nop // nop // nop // ****** r4000 errata nop // ****** r4000 errata tlbp // probe for entry in TB nop // 2 cycle hazzard nop // mfc0 t2,index // read result of probe nop // 1 cycle hazzard bltz t2,20f // if ltz, entry is not in TB li v0,FALSE // set to return failure tlbr // read entry from TB nop // 3 cycle hazzard nop // nop // nop // ****** r4000 errata nop // ****** r4000 errata sll t1,a0,0x1f - (ENTRYHI_VPN2 - 1) // shift low bit of VPN into sign bltzl t1,10f // if ltz, check second PTE mfc0 t1,entrylo1 // get second PTE for probe mfc0 t1,entrylo0 // get first PTE for probe 10: nop // 1 cycle hazzard sll t1,t1,0x1f - ENTRYLO_V // shift valid bit into sign position bgez t1,20f // if geq, entry is not valid srl t2,INDEX_INDEX // isolate index and t2,t2,0x3f // sltu v0,t2,FIXED_ENTRIES // check if entry in fixed part of TB .set at .set reorder 20: ENABLE_INTERRUPTS(t0) // enable interrupts .end KiProbeEntryTb SBTTL("Read Tb Entry") //++ // // VOID // KiReadEntryTb ( // IN ULONG Index, // OUT PULONG EntryLo[], // OUT PULONG EntryHi // ) // // Routine Description: // // This function is called to read an entry from the TB. // // Arguments: // // Index - Supplies the index of the entry to read. // // entrylo - Supplies a pointer to a array that receives the first and // second TB entry values. // // EntryHi - Supplies a pointer to a variable that receives the high // part of the TB entry. // // Return Value: // // None. // //-- LEAF_ENTRY(KiReadEntryTb) DISABLE_INTERRUPTS(t0) // disable interrupts .set noreorder .set noat sll a0,INDEX_INDEX // shift index into position mfc0 t1,entryhi // save entry high register mtc0 a0,index // set TB entry index nop // nop // ****** r4000 errate nop // ****** r4000 errate nop // ****** r4000 errate nop // ****** r4000 errate tlbr // read entry from TB nop // 3 cycle hazzard nop // nop // nop // ****** r4000 errate nop // ****** r4000 errate mfc0 t2,entrylo0 // save first PTE value mfc0 t3,entrylo1 // save second PTE value mfc0 t4,entryhi // save entry high register mtc0 t1,entryhi // restore entry high register nop // ****** r4000 errate nop // ****** r4000 errate nop // ****** r4000 errate nop // ****** r4000 errate nop // ****** r4000 errate .set at .set reorder ENABLE_INTERRUPTS(t0) // enable interrupts sw t2,0(a1) // set first PTE value sw t3,4(a1) // set second PTE value sw t4,0(a2) // set entry high register value j ra // return .end KiReadEntryTb SBTTL("Flush Write Buffer") //++ // // VOID // KeFlushWriteBuffer ( // VOID // ) // // Routine Description: // // This function flushes the write buffer on the current processor. // // Arguments: // // None. // // Return Value: // // None. // //-- LEAF_ENTRY(KeFlushWriteBuffer) j ra // return .end KeFlushWritebuffer //++ // // BOOLEAN // KiDisableInterrupts ( // VOID // ) // // Routine Description: // // This function disables interrupts and returns whether interrupts // were previously enabled. // // Arguments: // // None. // // Return Value: // // A boolean value that determines whether interrupts were previously // enabled (TRUE) or disabled(FALSE). // //-- LEAF_ENTRY(KiDisableInterrupts) .set noreorder .set noat mfc0 t0,psr // get current processor status li t1,~(1 << PSR_IE) // set interrupt enable mask and t2,t1,t0 // clear interrupt enable mtc0 t2,psr // disable interrupts and v0,t0,1 << PSR_IE // iosolate current interrupt enable srl v0,v0,PSR_IE // .set at .set reorder j ra // return .end KiDisableInterrupts SBTTL("Restore Interrupts") //++ // // VOID // KiRestoreInterrupts ( // IN BOOLEAN Enable // ) // // Routine Description: // // This function restores the interrupt enable that was returned by // the disable interrupts function. // // Arguments: // // Enable (a0) - Supplies the interrupt enable value. // // Return Value: // // None. // //-- LEAF_ENTRY(KiRestoreInterrupts) .set noreorder .set noat mfc0 t0,psr // get current processor status sll t1,a0,PSR_IE // shift previous enable into position or t1,t1,t0 // merge previous enable mtc0 t1,psr // restore previous interrupt enable nop // .set at .set reorder j ra // return .end KiRestoreInterrupts SBTTL("Generate Trap Frame") //++ // // Routine Desription: // // This routine is called to save the volatile integer and floating // registers in a trap frame. // // N.B. This routine uses a special argument passing mechanism and destroys // no registers. It is assumed that integer register AT is saved by the // caller. // // Arguments: // // s8 - Supplies a pointer to the base of an trap frame. // // Return Value: // // None. // //-- LEAF_ENTRY(KiGenerateTrapFrame) sw v0,TrIntV0(s8) // save integer register v0 sw v1,TrIntV1(s8) // save integer register v1 mflo v1 // save lo integer register sw v1,TrIntLo(s8) // mfhi v1 // save hi integer register sw v1,TrIntHi(s8) // lw v1,TrIntV1(s8) // restore integer register v1 sw a0,TrIntA0(s8) // save integer registers a0 - a3 sw a1,TrIntA1(s8) // sw a2,TrIntA2(s8) // sw a3,TrIntA3(s8) // sw t0,TrIntT0(s8) // save integer registers t0 - t9 sw t1,TrIntT1(s8) // sw t2,TrIntT2(s8) // sw t3,TrIntT3(s8) // sw t4,TrIntT4(s8) // sw t5,TrIntT5(s8) // sw t6,TrIntT6(s8) // sw t7,TrIntT7(s8) // sw t8,TrIntT8(s8) // sw t9,TrIntT9(s8) // #if defined(R3000) swc1 f0,TrFltF0(s8) // save floating register f0 #endif #if defined(R4000) sdc1 f0,TrFltF0(s8) // save floating register f0 #endif b KiSaveVolatileFloatState // save remainder of state .end KiGenerateTrapFrame SBTTL("Restore Trap Frame") //++ // // Routine Description: // // This routine is called to restore the volatile integer and floating // registers from a trap frame. // // N.B. This routine uses a special argument passing mechanism and destroys // no registers. It is assumed that integer register AT is restored by // the caller. // // Arguments: // // sp - Supplies a pointer to an exception frame. // // Return Value: // // None. // //-- LEAF_ENTRY(KiRestoreTrapFrame) lw v0,TrIntV0(s8) // restore integer register v0 lw v1,TrIntV1(s8) // restore integer register v1 lw a0,TrIntA0(s8) // restore integer registers a0 - a3 lw a1,TrIntA1(s8) // lw a2,TrIntA2(s8) // lw a3,TrIntA3(s8) // lw t0,TrIntLo(s8) // restore lo and hi integer registers lw t1,TrIntHi(s8) // mtlo t0 // mthi t1 // lw t0,TrIntT0(s8) // restore integer registers t0 - t9 lw t1,TrIntT1(s8) // lw t2,TrIntT2(s8) // lw t3,TrIntT3(s8) // lw t4,TrIntT4(s8) // lw t5,TrIntT5(s8) // lw t6,TrIntT6(s8) // lw t7,TrIntT7(s8) // lw t8,TrIntT8(s8) // lw t9,TrIntT9(s8) // #if defined(R3000) lwc1 f0,TrFltF0(s8) // restore floating register f0 #endif #if defined(R4000) ldc1 f0,TrFltF0(s8) // restore floating register f0 #endif b KiRestoreVolatileFloatState // restore remainder of state .end KiRestoreTrapFrame SBTTL("Save Volatile Floating Registers") //++ // // Routine Desription: // // This routine is called to save the volatile floating registers. // // N.B. This routine uses a special argument passing mechanism and destroys // no registers. It is assumed that floating register f0 is saved by the // caller. // // Arguments: // // s8 - Supplies a pointer to a trap frame. // // Return Value: // // None. // //-- LEAF_ENTRY(KiSaveVolatileFloatState) #if defined(R3000) swc1 f1,TrFltF1(s8) // save floating register f1 - f19 swc1 f2,TrFltF2(s8) // swc1 f3,TrFltF3(s8) // swc1 f4,TrFltF4(s8) // swc1 f5,TrFltF5(s8) // swc1 f6,TrFltF6(s8) // swc1 f7,TrFltF7(s8) // swc1 f8,TrFltF8(s8) // swc1 f9,TrFltF9(s8) // swc1 f10,TrFltF10(s8) // swc1 f11,TrFltF11(s8) // swc1 f12,TrFltF12(s8) // swc1 f13,TrFltF13(s8) // swc1 f14,TrFltF14(s8) // swc1 f15,TrFltF15(s8) // swc1 f16,TrFltF16(s8) // swc1 f17,TrFltF17(s8) // swc1 f18,TrFltF18(s8) // swc1 f19,TrFltF19(s8) // #endif #if defined(R4000) sdc1 f2,TrFltF2(s8) // save floating register f2 - f19 sdc1 f4,TrFltF4(s8) // sdc1 f6,TrFltF6(s8) // sdc1 f8,TrFltF8(s8) // sdc1 f10,TrFltF10(s8) // sdc1 f12,TrFltF12(s8) // sdc1 f14,TrFltF14(s8) // sdc1 f16,TrFltF16(s8) // sdc1 f18,TrFltF18(s8) // #endif j ra // return .end KiSaveVolatileFloatState) SBTTL("Restore Volatile Floating Registers") //++ // // Routine Desription: // // This routine is called to restore the volatile floating registers. // // N.B. This routine uses a special argument passing mechanism and destroys // no registers. It is assumed that floating register f0 is restored by // the caller. // // Arguments: // // s8 - Supplies a pointer to a trap frame. // // Return Value: // // None. // //-- LEAF_ENTRY(KiRestoreVolatileFloatState) #if defined(R3000) lwc1 f1,TrFltF1(s8) // restore floating registers f1 - f19 lwc1 f2,TrFltF2(s8) // lwc1 f3,TrFltF3(s8) // lwc1 f4,TrFltF4(s8) // lwc1 f5,TrFltF5(s8) // lwc1 f6,TrFltF6(s8) // lwc1 f7,TrFltF7(s8) // lwc1 f8,TrFltF8(s8) // lwc1 f9,TrFltF9(s8) // lwc1 f10,TrFltF10(s8) // lwc1 f11,TrFltF11(s8) // lwc1 f12,TrFltF12(s8) // lwc1 f13,TrFltF13(s8) // lwc1 f14,TrFltF14(s8) // lwc1 f15,TrFltF15(s8) // lwc1 f16,TrFltF16(s8) // lwc1 f17,TrFltF17(s8) // lwc1 f18,TrFltF18(s8) // lwc1 f19,TrFltF19(s8) // #endif #if defined(R4000) ldc1 f2,TrFltF2(s8) // restore floating registers f2 - f19 ldc1 f4,TrFltF4(s8) // ldc1 f6,TrFltF6(s8) // ldc1 f8,TrFltF8(s8) // ldc1 f10,TrFltF10(s8) // ldc1 f12,TrFltF12(s8) // ldc1 f14,TrFltF14(s8) // ldc1 f16,TrFltF16(s8) // ldc1 f18,TrFltF18(s8) // #endif j ra // return .end KiRestoreVolatileFloatState #endif