947 asm("cmp r3, #0 "); |
947 asm("cmp r3, #0 "); |
948 asm("ble 0f "); // thread isn't timesliced or timeslice already expired so skip |
948 asm("ble 0f "); // thread isn't timesliced or timeslice already expired so skip |
949 asm("cmp r12, #0 "); |
949 asm("cmp r12, #0 "); |
950 asm("bne 0f "); // initial (i.e. idle) thread, so skip |
950 asm("bne 0f "); // initial (i.e. idle) thread, so skip |
951 asm("ldr r3, [r2, #%a0]" : : "i" _FOFF(ArmLocalTimer,iTimerCount)); |
951 asm("ldr r3, [r2, #%a0]" : : "i" _FOFF(ArmLocalTimer,iTimerCount)); |
952 asm("ldr r12, [r0, #%a0]" : : "i" _FOFF(TSubScheduler,iSSX.iTimerPeriodM)); |
952 asm("ldr r12, [r0, #%a0]" : : "i" _FOFF(TSubScheduler,iSSX.iTimerFreqRI.iI.iM)); |
953 asm("ldr r2, [r0, #%a0]" : : "i" _FOFF(TSubScheduler,iSSX.iTimerPeriodS)); |
953 asm("ldr r2, [r0, #%a0]" : : "i" _FOFF(TSubScheduler,iSSX.iTimerFreqRI.iI.iX)); |
954 asm("cmp r3, #0 "); |
954 asm("cmp r3, #0 "); |
955 asm("movmi r0, #0 "); // if timer count is negative, save zero |
955 asm("movmi r0, #0 "); // if timer count is negative, save zero |
956 asm("bmi 1f "); |
956 asm("bmi 1f "); |
957 asm("umull r0, r3, r12, r3 "); // scale up to max timer clock (R3:R0) |
957 asm("mov r2, r2, lsl #16 "); |
|
958 asm("mov r2, r2, asr #16 "); |
|
959 asm("umull r0, r3, r12, r3 "); // scale up to max timer clock (R3:R0) - need to shift right by -iX |
|
960 asm("rsb r2, r2, #0 "); |
958 asm("rsb r12, r2, #32 "); |
961 asm("rsb r12, r2, #32 "); |
959 asm("movs r0, r0, lsr r2 "); // r0 >>= iSSX.iTimerPeriodS, C = last bit shifted off (rounding) |
962 asm("movs r0, r0, lsr r2 "); // r0 >>= iSSX.iTimerFreqRI.iI.iX, C = last bit shifted off (rounding) |
960 asm("orr r0, r0, r3, lsl r12 "); // bottom bits from r12 into top bits of r0 |
963 asm("orr r0, r0, r3, lsl r12 "); // bottom bits from r3 into top bits of r0 |
961 asm("adcs r0, r0, #0 "); // round using last bit shifted off |
964 asm("adcs r0, r0, #0 "); // round using last bit shifted off |
962 asm("1: "); |
965 asm("1: "); |
963 asm("str r0, [r1, #%a0]" : : "i" _FOFF(NThreadBase,iTime)); |
966 asm("str r0, [r1, #%a0]" : : "i" _FOFF(NThreadBase,iTime)); |
964 asm("0: "); |
967 asm("0: "); |
965 __JUMP(,lr); |
968 __JUMP(,lr); |
969 #if defined(__UTT_MACHINE_CODED__) |
972 #if defined(__UTT_MACHINE_CODED__) |
970 #if defined(__NKERN_TIMESTAMP_USE_LOCAL_TIMER__) |
973 #if defined(__NKERN_TIMESTAMP_USE_LOCAL_TIMER__) |
971 #error Use of local timer for NKern::Timestamp() no longer supported |
974 #error Use of local timer for NKern::Timestamp() no longer supported |
972 #else |
975 #else |
973 |
976 |
974 /* Update aOld's execution time and set up the timer for aNew |
977 #error UpdateThreadTimes assembler out of date! |
975 Update this CPU's timestamp value |
|
976 |
|
977 if (!aOld) aOld=iInitialThread |
|
978 if (!aNew) aNew=iInitialThread |
|
979 newcount = aNew->iTime>0 ? Max(aNew->iTime*iSSX.iTimerFreqM/2^(32+iTimerFreqS), 1) : 2^31-1 |
|
980 cli() |
|
981 oldcount = timer count |
|
982 if (oldcount<=0 || aOld!=aNew) |
|
983 { |
|
984 timer count = newcount |
|
985 iSSX.iLastTimerSet = newcount |
|
986 if (aOld!=aNew) |
|
987 { |
|
988 TUint64 now = NKern::Timestamp(); |
|
989 elapsed = iLastTimestamp -= now; |
|
990 iLastTimestamp = now; |
|
991 aOld->iTotalCpuTime.i64 += elapsed; |
|
992 if (!aOld->iActiveState) |
|
993 aOld->iTotalActiveTime.i64 += (now - aOld->iLastActivationTime.i64); |
|
994 ++iReschedCount.i64; |
|
995 ++aNew->iRunCount.i64; |
|
996 } |
|
997 } |
|
998 sti() |
|
999 */ |
|
1000 __NAKED__ void TSubScheduler::UpdateThreadTimes(NThreadBase* /*aOld*/, NThreadBase* /*aNew*/) |
|
1001 { |
|
1002 asm("cmp r2, #0 "); |
|
1003 asm("ldreq r2, [r0, #%a0]" : : "i" _FOFF(TSubScheduler,iInitialThread)); |
|
1004 asm("ldr r12, [r0, #%a0]" : : "i" _FOFF(TSubScheduler,iSSX.iTimerFreqM)); |
|
1005 asm("cmp r1, #0 "); |
|
1006 asm("ldreq r1, [r0, #%a0]" : : "i" _FOFF(TSubScheduler,iInitialThread)); |
|
1007 asm("ldr r3, [r2, #%a0]" : : "i" _FOFF(NThreadBase,iTime)); |
|
1008 asm("stmfd sp!, {r4-r7} "); |
|
1009 asm("cmp r1, r2 "); |
|
1010 asm("beq 2f "); |
|
1011 asm("ldr r6, [r2, #%a0]" : : "i" _FOFF(NThreadBase,iRunCount.i32[0])); |
|
1012 asm("ldr r7, [r2, #%a0]" : : "i" _FOFF(NThreadBase,iRunCount.i32[1])); |
|
1013 asm("adds r6, r6, #1 "); |
|
1014 asm("str r6, [r2, #%a0]" : : "i" _FOFF(NThreadBase,iRunCount.i32[0])); |
|
1015 asm("ldr r4, [r0, #%a0]" : : "i" _FOFF(TSubScheduler,iReschedCount.i32[0])); |
|
1016 asm("ldr r6, [r0, #%a0]" : : "i" _FOFF(TSubScheduler,iReschedCount.i32[1])); |
|
1017 asm("adcs r7, r7, #0 "); |
|
1018 asm("str r7, [r2, #%a0]" : : "i" _FOFF(NThreadBase,iRunCount.i32[1])); |
|
1019 asm("adds r4, r4, #1 "); |
|
1020 asm("adcs r6, r6, #0 "); |
|
1021 asm("str r4, [r0, #%a0]" : : "i" _FOFF(TSubScheduler,iReschedCount.i32[0])); |
|
1022 asm("str r6, [r0, #%a0]" : : "i" _FOFF(TSubScheduler,iReschedCount.i32[1])); |
|
1023 asm("2: "); |
|
1024 asm("ldr r6, [r0, #%a0]" : : "i" _FOFF(TSubScheduler,iSSX.iLocalTimerAddr)); |
|
1025 asm("cmp r3, #1 "); // aNew->iTime > 0 ? |
|
1026 asm("movlt r3, #0x7fffffff "); // if not, use 2^31-1 |
|
1027 asm("blt 3f "); |
|
1028 asm("cmp r1, r2 "); // different thread? |
|
1029 asm("beq 0f "); // no - finish |
|
1030 asm("ldr r5, [r0, #%a0]" : : "i" _FOFF(TSubScheduler,iSSX.iTimerFreqS)); |
|
1031 asm("umull r4, r3, r12, r3 "); // r3:r4 = aNew->iTime * iTimerFreqM |
|
1032 asm("adds r4, r4, r4 "); // bit 31 into C |
|
1033 asm("teq r5, #0 "); // check for iTimerFreqS=0 without changing C |
|
1034 asm("movnes r3, r3, lsr r5 "); // if not, r3>>=iTimerFreqS, last bit shifted out into C |
|
1035 asm("adcs r3, r3, #0 "); // round using last bit shifted off |
|
1036 asm("3: "); |
|
1037 asm("str r3, [r0, #%a0]" : : "i" _FOFF(TSubScheduler,iSSX.iLastTimerSet)); |
|
1038 asm("str r3, [r6, #%a0]" : : "i" _FOFF(ArmLocalTimer,iTimerCount)); // set new timeslice value in timer |
|
1039 |
|
1040 asm("ldr r6, [r0, #%a0]" : : "i" _FOFF(TSubScheduler,iLastTimestamp.i32[0])); |
|
1041 asm("ldr r7, [r0, #%a0]" : : "i" _FOFF(TSubScheduler,iLastTimestamp.i32[1])); |
|
1042 asm("stmfd sp!, {r0-r2,lr} "); |
|
1043 asm("bl Timestamp__5NKern "); // R1:R0 = current time |
|
1044 asm("mov r4, r0 "); |
|
1045 asm("mov r5, r1 "); // R5:R4 = current time |
|
1046 asm("ldmfd sp!, {r0-r2,lr} "); |
|
1047 asm("str r4, [r0, #%a0]" : : "i" _FOFF(TSubScheduler,iLastTimestamp.i32[0])); |
|
1048 asm("ldr r3, [r1, #%a0]!" : : "i" _FOFF(NThreadBase,iTotalCpuTime.i64)); |
|
1049 asm("ldr r12, [r1, #4] "); |
|
1050 asm("str r5, [r0, #%a0]" : : "i" _FOFF(TSubScheduler,iLastTimestamp.i32[1])); |
|
1051 asm("stmdb r1, {r4-r5} "); // aOld->iLastRunTime |
|
1052 asm("ldrb r2, [r1, #%a0]" : : "i" (_FOFF(NSchedulable,iActiveState)-_FOFF(NThreadBase,iTotalCpuTime.i64))); |
|
1053 asm("subs r6, r4, r6 "); |
|
1054 asm("sbcs r7, r5, r7 "); // R7:R6 = time since last reschedule |
|
1055 asm("adds r3, r3, r6 "); |
|
1056 asm("adcs r12, r12, r7 "); // total CPU time of old thread |
|
1057 asm("stmia r1!, {r3,r12} "); // store, r1=&aOld.iLastActivationTime |
|
1058 asm("cmp r2, #0 "); // old thread still active? |
|
1059 asm("bne 0f "); // yes - done |
|
1060 asm("ldmia r1!, {r2,r3,r6,r7} "); // R3:R2 = last activation time, R7:R6=total active time |
|
1061 asm("subs r2, r4, r2 "); |
|
1062 asm("sbcs r3, r5, r3 "); // R3:R2 = time since last activation |
|
1063 asm("adds r6, r6, r2 "); |
|
1064 asm("adcs r7, r7, r3 "); // R7:R6 = new total active time |
|
1065 asm("stmdb r1, {r6,r7} "); |
|
1066 |
|
1067 asm("0: "); |
|
1068 asm("ldmfd sp!, {r4-r7} "); |
|
1069 __JUMP(,lr); |
|
1070 } |
|
1071 |
978 |
1072 #endif |
979 #endif |
1073 #endif // __UTT_MACHINE_CODED__ |
980 #endif // __UTT_MACHINE_CODED__ |