//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/x4clock.s,v 1.6 1996/03/12 14:56:20 pierre Exp $") // TITLE("Interval and Profile Clock Interrupts") //++ // // Copyright (c) 1991 Microsoft Corporation // // Module Name: // // x4clock.s // // Abstract: // // This module implements the code necessary to field and process the // interval and profile clock interrupts on a MIPS R4000 system. // // Environment: // // Kernel mode only. // // //-- #include "halmips.h" #include "SNIdef.h" #define MPA_TIMER_MESSAGE 11 /* timer interrupt */ SBTTL("System Clock Interrupt") //++ // // Routine Description: // // This routine is entered as the result of an interrupt generated by // the interval timer. Its function is to acknowledge the interrupt and // transfer control to the standard system routine to update the system // time and the execution time of the current thread and process. // // Arguments: // // s8 - Supplies a pointer to a trap frame. // // Return Value: // // None. // //-- .struct 0 CiArgs: .space 4 * 4 // saved arguments .space 3 * 4 // fill CiRa: .space 4 // saved return address CiFrameLength: // NESTED_ENTRY(HalpClockInterrupt, CiFrameLength, zero) subu sp,sp,CiFrameLength // allocate stack frame sw ra,CiRa(sp) // save return address PROLOGUE_END move a0,s8 // set address of trap frame lw a1,HalpCurrentTimeIncrement lw t0,__imp_KeUpdateSystemTime // update system time jal t0 // // // we use this only when we have the machine up and running ... // LED's can show us something, what we do not see in the debugger // la t0,HalpLedRegister // get current Value of LED Register lw a0,0(t0) addu a0,a0,1 // increment sw a0,0(t0) // store and lw t0,HalpIsTowerPci beq t0,zero,2f jal HalpPciTowerDisplayLed b 3f 2: la t0, HalpLedAddress // get address of the variable lw t0,0(t0) // get value sb a0,0(t0) // display LSByte (set the LED) // // At each clock interrupt the next time increment is moved to the current // time increment to "pipeline" the update of the current increment at the // correct time. If the new time increment is nonzero, then the new time // increment is moved to the next time increment and the timer is reprogramed // 3: lw t0,KdDebuggerEnabled // get address of debugger enable lw t1,HalpNewTimeIncrement // get new time increment lw t2,HalpNextTimeIncrement // get the next increment value lbu t0,0(t0) // get debugger enable flag lw ra,CiRa(sp) // restore return address or t4,t1,t0 // new interval count or debugger? sw t2,HalpCurrentTimeIncrement // pipeline current increment value bne zero,t4,10f // if ne, interval change or debugger addu sp,sp,CiFrameLength // deallocate stack frame j ra // return // // The interval count must be changed or the debugger is enabled. // 10: sw zero,HalpNewTimeIncrement // clear new time increment beq zero,t1,15f // if eq, not interval count change sw t1,HalpNextTimeIncrement // set next time increment value move a0,t1 // prepare to call HalpProgramIntervalTimer jal HalpProgramIntervalTimer // program timer chip ... 15: beq zero,t0,40f // if eq, debugger not enabled jal KdPollBreakIn // check if breakin is requested beq zero,v0,40f // if eq, no breakin requested break BREAKIN_BREAKPOINT // break into the debugger 40: lw ra,CiRa(sp) // restore return address addu sp,sp,CiFrameLength // deallocate stack frame j ra // return .end HalpClockInterrupt SBTTL("System Clock Interrupt - Processor N") //++ // // Routine Description: // // This routine is entered as the result of an interrupt generated by // the extra interval timer in the slave processors. Its function is // to transfer control to the standard system routine to update the // execution time of the current thread and process. // // Note: We plan to use the extra timer for our MultiProcessor (SNI)Machine // MAYBE, if we have arbitrated interrupts, we have to acknowledge // this interrupt here and send an message to the other processors // (Quadro machine) // // Arguments: // // s8 - Supplies a pointer to a trap frame. // // Return Value: // // None. // //-- NESTED_ENTRY(HalpClockInterrupt1, CiFrameLength, zero) subu sp,sp,CiFrameLength // allocate stack frame sw ra,CiRa(sp) // save return address PROLOGUE_END li a0,0x1000 jal HalpCheckSpuriousInt beq v0,0,10f lw ra,CiRa(sp) // restore return address addu sp,sp,CiFrameLength // deallocate stack frame j ra 10: li t0, PCI_EXTRA_TIMER_ACK_ADDR // get address of acknowledge register sb zero,0(t0) // acknowledge timer interrupt move a0,s8 // set address of trap frame lw t1,__imp_KeUpdateRunTime // update system runtime lw ra,CiRa(sp) // restore return address addu sp,sp,CiFrameLength // deallocate stack frame j t1 // .end HalpClockInterrupt1 SBTTL("System Clock Interrupt - Processor N") //++ // // Routine Description: // // This routine is entered as the result of an interrupt generated by // the extra interval timer in the slave processors. Its function is // to transfer control to the standard system routine to update the // execution time of the current thread and process. // // We use the extra timer for our MultiProcessor (SNI)Machine // we have to acknowledge // this interrupt here and send an message to the other processors // (Quadro machine) // // Arguments: // // s8 - Supplies a pointer to a trap frame. // // Return Value: // // None. // //-- NESTED_ENTRY(HalpClockInterruptPciTower, CiFrameLength, zero) subu sp,sp,CiFrameLength // allocate stack frame sw ra,CiRa(sp) // save return address PROLOGUE_END // // Send a "TIMER" ipi // lw a0,HalpIsMulti // test if more than 2 procs li a1,2 slt a2,a1,a0 beq a2,0,10f // if no more than 2 proc , no need to send Ipi li a0,0xc // send IPI to proc 2 and 3 li a1,MPA_TIMER_MESSAGE jal HalpRequestIpi 10: move a0,s8 // set address of trap frame lw t1,__imp_KeUpdateRunTime // update system runtime lw ra,CiRa(sp) // restore return address addu sp,sp,CiFrameLength // deallocate stack frame j t1 // .end HalpClockInterruptPciTower SBTTL("Profile Clock Interrupt") //++ // // Routine Description: // // This routine is entered as the result of an interrupt generated by the // profile clock. Its function is to acknowledge the profile interrupt, // compute the next compare value, update the performance counter, and // transfer control to the standard system routine to process any active // profiles. // // Arguments: // // s8 - Supplies a pointer to a trap frame. // // Return Value: // // None. // //-- NESTED_ENTRY(HalpProfileInterrupt, CiFrameLength, zero) subu sp,sp,CiFrameLength // allocate stack frame sw ra,CiRa(sp) // save return address PROLOGUE_END // li a0,0x8000 // jal HalpCheckSpuriousInt // beq v0,zero,10f // lw ra,CiRa(sp) // restore return address // addu sp,sp,CiFrameLength // deallocate stack frame // j ra 10: .set noreorder .set noat mfc0 t1,count // get current count value mfc0 t0,compare // get current comparison value addu t1,t1,8 // factor in lost cycles subu t1,t1,t0 // compute initial count value mtc0 t0,compare // dismiss interrupt mtc0 t1,count // set new count register value .set at .set reorder // // we prefer the MultiPro version, which also works on UniPro machines // lw t1,KiPcr + PcPrcb(zero) // get current processor block address la t2,HalpPerformanceCounter // get performance counter address lbu t1,PbNumber(t1) // get processor number sll t1,t1,3 // compute address of performance count addu t1,t1,t2 // lw t2,LiLowPart(t1) // get low part of performance count lw t3,LiHighPart(t1) // get high part of performance count addu t2,t2,t0 // update low part of performance count sw t2,LiLowPart(t1) // store low part of performance count sltu t4,t2,t0 // generate carry into high part addu t3,t3,t4 // update high part of performance count sw t3,LiHighPart(t1) // store high part of performance count li a0,0x00 move a0,s8 // set address of trap frame lw t4,__imp_KeProfileInterrupt // process profile interrupt jal t4 // jal HalpCheckSpuriousInt lw ra,CiRa(sp) // restore return address addu sp,sp,CiFrameLength // deallocate stack frame j ra .end HalpProfileInterrupt SBTTL("Read Count Register") //++ // // ULONG // HalpReadCountRegister ( // VOID // ); // // Routine Description: // // This routine reads the current value of the count register and // returns the value. // // Arguments: // // None. // // Return Value: // // Current value of the count register. // //-- LEAF_ENTRY(HalpReadCountRegister) .set noreorder .set noat mfc0 v0,count // get count register value .set at .set reorder j ra // return .end HalpReadCountRegister SBTTL("Write Compare Register And Clear") //++ // // ULONG // HalpWriteCompareRegisterAndClear ( // IN ULONG Value // ); // // Routine Description: // // This routine reads the current value of the count register, writes // the value of the compare register, clears the count register, and // returns the previous value of the count register. // // Arguments: // // Value - Supplies the value written to the compare register. // // Return Value: // // Previous value of the count register. // //-- LEAF_ENTRY(HalpWriteCompareRegisterAndClear) .set noreorder .set noat mfc0 v0,count // get count register value mtc0 a0,compare // set compare register value li t0,7 // set lost cycle count mtc0 t0,count // set count register to zero .set at .set reorder j ra // return .end HalpWriteCompareRegisterAndClear NESTED_ENTRY(HalpPciTowerDisplayLed, CiFrameLength, zero) subu sp,sp,CiFrameLength // allocate stack frame sw ra,CiRa(sp) // save return address PROLOGUE_END // // code for PCI tower // li t5,8, divu a0,t5 mfhi t4 li t5,1 .word 0x018d2004 # sllv a0,t5,t4 // t4 -> temp-reg. // t5 -> low-reg. 32 bits // t6 -> high-reg. 32 bits and t5,a0,0x01 # bit0 shift to bit0(LED0) and t4,a0,0x02 # bit1 shift to bit16(LED1) sll t4,t4,16-1 or t5,t5,t4 and t4,a0,0x04 # bit2 shift to bit32(LED2) -> bit0/high_reg. srl t6,t4,2-0 and t4,a0,0x08 # bit3 shift to bit48(LED3) -> bit16/high_reg. sll t4,t4,16-3 or t6,t6,t4 and t4,a0,0x10 # bit4 shift to bit1(LED4) srl t4,t4,4-1 or t5,t5,t4 and t4,a0,0x20 # bit5 shift to bit17(LED5) sll t4,t4,17-5 or t5,t5,t4 and t4,a0,0x40 # bit6 shift to bit33(LED6) -> bit1/high_reg. srl t4,t4,6-1 or t6,t6,t4 and t4,a0,0x80 # bit7 shift to bit49(LED7) -> bit17/high_reg. sll t4,t4,17-7 or t6,t6,t4 lw a1,HalpLedAddress lw t4,0(a1) and t4,t4,PCI_TOWER_LED_MASK # led mask or t4,t4,t5 # t5 -> low 32 bits sw t4,0(a1) jal KeFlushWriteBuffer lw a1,HalpLedAddress lw t4,4(a1) and t4,t4,PCI_TOWER_LED_MASK # led mask or t4,t4,t6 # t6 -> high 32 bits sw t4,4(a1) jal KeFlushWriteBuffer lw ra,CiRa(sp) // restore return address addu sp,sp,CiFrameLength // deallocate stack frame j ra .end HalpPciTowerDisplayLed // // end code for PCI 1tower //