;	AUTO-GENERATED SYMBOL LIST
;	IMPORTS:
;	  NKConsoleLog
;	    getchar
;	    printb
;	    printd
;	    printh
;	    printw
;	  NKIndex
;	    DeleteID
;	    LookupID
;	  NKPoolAllocator
;	    PoolAllocClear
;	    PoolFree
;	  NKScheduler
;	    CalculateTimeslice
;	    FlagSchEvaluationIfTaskRequires
;	    SchRdyTaskNow
;	    SchTaskUnrdy
;	    clear_cr0_lt
;	    major_0x149d4
;	  NKSync
;	    EnqueueMessage
;	    SetEvent
;	    SignalSemaphore
;	  NKThud
;	    panic
;	    panic_non_interactive
;	EXPORTS:
;	  DequeueTimer (=> NKMPCalls, NKPrimaryIntHandlers, NKSync, NKTasks)
;	  EnqueueTimer (=> NKMPCalls, NKSync)
;	  GetTime (=> NKMPCalls, NKScheduler, NKSync, NKTasks)
;	  InitTMRQs (=> NKInit)
;	  SetTimesliceFromCurTime (=> NKScheduler)
;	  StartTimeslicing (=> NKInit)
;	  TimebaseTicksPerPeriod (=> NKScheduler, NKSync)
;	  TimerDispatch (=> NKInterrupts)


Local_Panic		set		*
				b		panic



InitTMRQs	;	OUTSIDE REFERER
	addi	r9, r1, PSA.TimerQueue
	lis		r8,  0x544d
	ori		r8, r8,  0x5251
	stw		r8,  0x0004(r9)
	stw		r9,  0x0008(r9)
	stw		r9,  0x000c(r9)
	li		r8,  0x00
	stb		r8,  0x0014(r9)
	li		r8,  0x01
	stb		r8,  0x0016(r9)
	stb		r8,  0x0017(r9)
	lis		r8,  0x7fff
	ori		r8, r8,  0xffff
	mtspr	dec, r8
	stw		r8,  0x0038(r9)
	oris	r8, r8,  0xffff
	stw		r8,  0x003c(r9)
	mfspr	r8, pvr
	rlwinm.	r8, r8,  0,  0, 14
	beq		InitTMRQs_0x7c
	mflr	r30
	li		r8,  0x40

;	r1 = kdp
;	r8 = size
	bl		PoolAllocClear
;	r8 = ptr

	mr.		r31, r8
	beq		Local_Panic
	stw		r31, PSA.OtherTimerQueuePtr(r1)
	li		r9,  0x07
	stb		r9,  0x0014(r31)
	li		r9,  0x01
	stb		r9,  0x0016(r31)
	mtlr	r30

InitTMRQs_0x7c
	mfspr	r8, pvr
	rlwinm.	r8, r8,  0,  0, 14
	beq		InitTMRQs_0xb4
	mflr	r30
	li		r8,  0x40

;	r1 = kdp
;	r8 = size
	bl		PoolAllocClear
;	r8 = ptr

	mr.		r31, r8
	beq		Local_Panic
	stw		r31, PSA._364(r1)
	li		r9,  0x08
	stb		r9,  0x0014(r31)
	li		r9,  0x01
	stb		r9,  0x0016(r31)
	mtlr	r30

InitTMRQs_0xb4


;	Activate the NanoDebugger (whatever that is...)

	lwz		r30, KDP.PA_ConfigInfo(r1)
	lhz		r31, NKConfigurationInfo.Debug(r30)
	cmplwi	r31, NKConfigurationInfo.DebugThreshold
	blt		@nodebug

	lwz		r31, NKConfigurationInfo.DebugFlags(r30)
	rlwinm.	r8, r31, 0, NKConfigurationInfo.NanodbgrFlagBit, NKConfigurationInfo.NanodbgrFlagBit
	beq		@nodebug

	lwz		r8, KDP.NanoKernelInfo + NKNanoKernelInfo.ConfigFlags(r1)
	_bset	r8, r8, NKNanoKernelInfo.NanodbgrFlagBit
	stw		r8, KDP.NanoKernelInfo + NKNanoKernelInfo.ConfigFlags(r1)

	mflr	r30

	li		r8, Timer.Size
	bl		PoolAllocClear					;	one of those weird queue structures
	mr.		r31, r8
	beq		Local_Panic

	li		r9, Timer.kKind6
	stb		r9, Timer.Kind(r31)

	li		r9, 1
	stb		r9, Timer.KeepAfterFiring(r31)

	bl		GetTime
	stw		r8, Timer.Time(r31)
	stw		r9, Timer.Time+4(r31)

	mr		r8, r31
	bl		EnqueueTimer

	_log	'Nanodebugger activated.^n'

	mtlr	r30
@nodebug
	blr



TimerTable

	dc.l	TimerFireUnknownKind - NKTop	; Timer.kKind0
	dc.l	TimerFire1 - NKTop				; Timer.kKind1
	dc.l	TimerFire2 - NKTop				; Timer.kKind2
	dc.l	TimerFire3 - NKTop				; Timer.kKind3
	dc.l	TimerFire4 - NKTop				; Timer.kKind4
	dc.l	TimerFire5 - NKTop				; Timer.kKind5
	dc.l	TimerFire6 - NKTop				; Timer.kKind6
	dc.l	TimerFire7 - NKTop				; Timer.kKind7
	dc.l	TimerFire8 - NKTop				; Timer.kKind8

TimerDispatch	;	OUTSIDE REFERER
	mflr	r19
	mfsprg	r18, 0
	stw		r19, EWA.TimerDispatchLR(r18)

TimerDispatch_0x30	;	OUTSIDE REFERER
	mfspr	r8, pvr
	rlwinm.	r8, r8,  0,  0, 14
	beq		@is_601

;not 601
@gettime_loop_non_601
	mftbu	r8
	mftb	r9
	mftbu	r16
	cmpw	r8, r16
	bne-	@gettime_loop_non_601
	b		@common

@is_601
@gettime_loop_601
	mfspr	r8, rtcu
	mfspr	r9, rtcl
	mfspr	r16, rtcu
	cmpw	r8, r16
	bne-	@gettime_loop_601

	dialect	POWER

	liu		r16, 1000000000 >> 16
	oril	r16, r16, 1000000000 & 0xffff

	mfmq	r17
	mul		r8, r16, r8
	mfmq	r16
	mtmq	r17
	
	mfxer	r17
	a		r9, r16, r9
	aze		r8, r8
	mtxer	r17

	dialect	PowerPC
@common



	lbz		r19, EWA.GlobalTimeIsValid(r18)
	addi	r30, r18, EWA.Base
	cmpwi	r19, 1
	lwz		r16, EWA.GlobalTime - EWA.Base(r30)
	bne		timer_earlier_than_sometime
	lwz		r17, EWA.GlobalTime + 4 - EWA.Base(r30)

	_b_if_time_gt	r16, r8, timer_earlier_than_sometime
@skipbranch
	li		r19,  0x00
	stw		r30, -0x0254(r18)
	stb		r19,  0x0017(r30)
	b		TimerFire4_0x10

timer_earlier_than_sometime
	lwz		r30, PSA.TimerQueue + LLL.Next(r1)
	lwz		r16,  0x0038(r30)
	lwz		r17,  0x003c(r30)

	_b_if_time_gt	r16, r8, TimerDispatch_0x188

	RemoveFromList		r30, scratch1=r19, scratch2=r20
	lwz		r19,  0x064c(r1)
	lbz		r20, Timer.Kind(r30)
	rlwimi	r19, r20,  2, 23, 29
	cmplwi	r20,  0x09
	llabel	r20, TimerTable
	li		r21,  0x00
	add		r20, r20, r19
	bgel	Local_Panic
	stb		r21,  0x0017(r30)
	lwz		r20,  0x0000(r20)
	add		r20, r20, r19
	mtlr	r20
	stw		r30, -0x0254(r18)
	blr

TimerDispatch_0x144
	mfsprg	r18, 0
	lwz		r30, -0x0254(r18)
	lbz		r19,  0x0016(r30)
	cmpwi	r19,  0x01
	lwz		r8,  0x0000(r30)
	beq		TimerDispatch_0x30
	bl		DeleteID
	mr		r8, r30
	bl		PoolFree
	lwz		r8,  0x001c(r30)
	cmpwi	r8,  0x00
	beq		TimerDispatch_0x180
	bl		PoolFree
	li		r8,  0x00
	stw		r8,  0x001c(r30)

TimerDispatch_0x180:
	mfsprg	r18, 0
	b		TimerDispatch_0x30

TimerDispatch_0x188
	lwz		r19, EWA.TimerDispatchLR(r18)
	mtlr	r19
	b		SetTimesliceFromCurTimeAndTripTime



StartTimeslicing	;	OUTSIDE REFERER
	mfsprg	r19, 0

	li		r8, 1
	stb		r8, EWA.GlobalTimeIsValid(r19)

	li		r8, 0
	stw		r8, EWA.GlobalTime(r19)
	stw		r8, EWA.GlobalTime + 4(r19)
	
	mflr	r19
	_log	'Starting timeslicing^n'
	mtlr	r19




;	CLOB	r8/r9, r16-r21

SetTimeslice

	mflr	r19
	bl		GetTime
	mtlr	r19




;	ARG		TimeBase r8/r9 curTime
;	CLOB	r16-r21

SetTimesliceFromCurTime

;	This should get the most distant time???
	lwz		r18, PSA.TimerQueue + LLL.Next(r1)
	lwz		r16, Timer.Time(r18)
	lwz		r17, Timer.Time+4(r18)




;	ARG		TimeBase r8/r9 curTime, TimeBase r16/r17 TripTime
;	CLOB	r18-r21

SetTimesliceFromCurTimeAndTripTime

	mfxer	r20
	mfsprg	r19, 0

	lis		r21, 0x7fff
	lbz		r18, EWA.GlobalTimeIsValid(r19)
	ori		r21, r21, 0xffff
	cmpwi	r18, 1

	;	r16/r17 = soonest(last timer, global PSA time if available)

	bne		global_time_invalid
	lwz		r18, EWA.GlobalTime(r19)
	lwz		r19, EWA.GlobalTime+4(r19)

	_b_if_time_le	r16, r18, last_timer_fires_sooner
	mr		r17, r19
	mr		r16, r18
last_timer_fires_sooner
global_time_invalid


	;	Subtract the current time (or what we were passed in r8/r9) from that time
	subfc	r17, r9, r17
	subfe.	r16, r8, r16
	mtxer	r20

	blt		@that_time_has_passed				;	hi bit of r16 = 1
	bne		@that_time_is_in_future				;	
	cmplw	r16, r21							;	typo? should be r17???
	bgt		@that_time_is_in_future				;	will never be taken...

;	When the times are roughly equal?
	mtspr	dec, r17
	blr

@that_time_is_in_future
	mtspr	dec, r21
	blr

@that_time_has_passed
	mtspr	dec, r21
	mtspr	dec, r16							;	this makes nearly no sense!
	blr



;	                     TimerFire0                      

TimerFireUnknownKind
	_log	'TimerInformation.kind is zero??^n'



;	                     TimerFire1                      

TimerFire1	;	OUTSIDE REFERER
	bl		Local_Panic
	lwz		r18,  0x0018(r30)
	stw		r16,  0x0080(r18)
	stw		r17,  0x0084(r18)
	lwz		r8,  0x0018(r30)
	li		r16,  0x00
	lbz		r17,  0x0018(r8)
	lwz		r19,  0x0088(r8)
	cmpwi	r17,  0x00
	stw		r16,  0x011c(r19)
	bne		TimerFire1_0x64
	addi	r16, r8,  0x08
	RemoveFromList		r16, scratch1=r17, scratch2=r19
	li		r17,  0x01
	stb		r17,  0x0019(r8)
	bl		SchRdyTaskNow
	bl		CalculateTimeslice
	bl		FlagSchEvaluationIfTaskRequires
	b		TimerDispatch_0x144

TimerFire1_0x64
	lwz		r16,  0x0064(r8)
	rlwinm.	r16, r16,  0, 30, 30



;	                     TimerFire2                      

TimerFire2	;	OUTSIDE REFERER
	bne		TimerDispatch_0x144
	bl		Local_Panic
	lwz		r18,  0x0018(r30)
	stw		r16,  0x0080(r18)
	stw		r17,  0x0084(r18)
	lwz		r8,  0x0018(r30)
	li		r16, -0x7270
	lbz		r17,  0x0018(r8)
	lwz		r18,  0x0088(r8)
	cmpwi	r17,  0x00
	bne		TimerFire3_0x8
	stw		r16,  0x011c(r18)
	lwz		r8,  0x0008(r8)
	lwz		r8,  0x0000(r8)

;	r8 = id
 	bl		LookupID
	cmpwi	r9, Queue.kIDClass

	cmpwi	cr1, r9,  0x05
	beq		TimerFire2_0x8c
	beq		cr1, TimerFire2_0x7c
	cmpwi	r9,  0x09
	cmpwi	cr1, r9,  0x06
	beq		TimerFire2_0x6c
	bne		cr1, Local_Panic
	lwz		r16,  0x0020(r8)
	addi	r16, r16, -0x01
	stw		r16,  0x0020(r8)
	b		TimerFire2_0x98

TimerFire2_0x6c
	lwz		r16,  0x001c(r8)
	addi	r16, r16, -0x01
	stw		r16,  0x001c(r8)
	b		TimerFire2_0x98

TimerFire2_0x7c
	lwz		r16,  0x001c(r8)
	addi	r16, r16, -0x01
	stw		r16,  0x001c(r8)
	b		TimerFire2_0x98

TimerFire2_0x8c
	lwz		r16,  0x002c(r8)
	addi	r16, r16, -0x01
	stw		r16,  0x002c(r8)

TimerFire2_0x98
	lwz		r8,  0x0018(r30)
	addi	r16, r8,  0x08
	RemoveFromList		r16, scratch1=r17, scratch2=r18
	bl		SchRdyTaskNow



;	                     TimerFire3                      

TimerFire3	;	OUTSIDE REFERER
	bl		FlagSchEvaluationIfTaskRequires
	b		TimerDispatch_0x144

TimerFire3_0x8	;	OUTSIDE REFERER
	b		Local_Panic



;	                     major_0x13258                      

;	Dead code -- probably removed from TimerTable

	lwz		r8,  0x0018(r30)

;	r8 = id
 	bl		LookupID
	cmpwi	r9, Queue.kIDClass

	mr		r31, r8
	bne		major_0x13258_0x68
	lwz		r16,  0x0024(r31)
	lwz		r8,  0x001c(r30)
	cmpwi	r16,  0x00
	cmpwi	cr1, r8,  0x00
	beq		major_0x13258_0x40
	lwz		r17,  0x0028(r31)
	mr.		r8, r17
	lwz		r17,  0x0008(r17)
	beq		major_0x13258_0x68
	stw		r17,  0x0028(r31)
	b		major_0x13258_0x4c

major_0x13258_0x40
	beq		cr1, major_0x13258_0x68
	li		r16,  0x00
	stw		r16,  0x001c(r30)

major_0x13258_0x4c
	lwz		r16,  0x0020(r30)
	lwz		r17,  0x0024(r30)
	lwz		r18,  0x0028(r30)
	stw		r16,  0x0010(r8)
	stw		r17,  0x0014(r8)
	stw		r18,  0x0018(r8)
	bl		EnqueueMessage		; Message *r8, Queue *r31

major_0x13258_0x68
	lwz		r8,  0x0034(r30)

;	r8 = id
 	bl		LookupID
	cmpwi	r9, Semaphore.kIDClass

	mr		r31, r8
	bne		major_0x13258_0x80
	bl		SignalSemaphore

major_0x13258_0x80
	lwz		r8,  0x002c(r30)

;	r8 = id
 	bl		LookupID
	cmpwi	r9, EventGroup.kIDClass

	mr		r31, r8



;	                     TimerFire4                      

TimerFire4	;	OUTSIDE REFERER
	bne		TimerFire4_0xc
	lwz		r8,  0x0030(r30)
	bl		SetEvent

TimerFire4_0xc
	b		TimerDispatch_0x144

TimerFire4_0x10	;	OUTSIDE REFERER
	mfsprg	r28, 0
	lwz		r29, -0x0008(r28)
	mr		r8, r29
	bl		SchTaskUnrdy
	lbz		r17,  0x0019(r29)
	cmpwi	r17,  0x02
	bge		TimerFire4_0x64
	mr		r8, r29
	lwz		r16,  0x0038(r30)
	lwz		r17,  0x003c(r30)
	bl		clear_cr0_lt
	bge		TimerFire4_0x50
	mr		r8, r29
	bl		SchRdyTaskNow
	bl		CalculateTimeslice
	b		TimerFire5_0x8

TimerFire4_0x50
	li		r18,  0x02
	stb		r18,  0x0019(r29)
	mr		r8, r29
	bl		SchRdyTaskNow
	b		TimerFire5_0x8

TimerFire4_0x64
	mr		r8, r29



;	                     TimerFire5                      

TimerFire5	;	OUTSIDE REFERER
	bl		SchRdyTaskNow
	bl		major_0x149d4

TimerFire5_0x8	;	OUTSIDE REFERER
	bl		FlagSchEvaluationIfTaskRequires
	mfsprg	r18, 0
	b		TimerDispatch_0x30



;	                     major_0x13364                      

;	Dead code -- probably removed from TimerTable

	_log	'Heartbeat: Ext '
	lwz		r16, KDP.NanoKernelInfo + NKNanoKernelInfo.ExternalIntCount(r1)
	mr		r8, r16
	bl		printd

	_log	'Alerts '
	lwz		r16, KDP.NanoKernelInfo + NKNanoKernelInfo.AlertCount(r1)
	mr		r8, r16
	bl		printd

	_log	'Blue cpu-'
	lwz		r17, PSA.PA_BlueTask(r1)
	lhz		r16, Task.CPUIndex(r17)
	mr		r8, r16
	bl		printb

	_log	'state-'
	lbz		r16, Task.State(r17)
	mr		r8, r16
	bl		printb

	_log	'scr-'
	lwz		r16, KDP.PA_ECB(r1)
	lwz		r18, KDP.PostIntMaskInit(r1)
	lwz		r16, ContextBlock.CR(r16)
	and		r16, r16, r18
	mr		r8, r16
	bl		printw

	_log	'mcr-'
	lwz		r16, PSA.MCR(r1)
	mr		r8, r16
	bl		printw

	_log	'IPL-'
	lwz		r16, KDP.PA_EmulatorIplValue(r1)
	lhz		r16, 0(r16)
	mr		r8, r16
	bl		printh

	_log	'eSR-'
	lwz		r16, KDP.PA_ECB(r1)
	lwz		r16, ContextBlock.r25(r16)
	andi.	r16, r16, 7
	mr		r8, r16
	bl		printb
	_log	'^n'

	mfxer	r19
	lwz		r16,  0x0038(r30)
	lwz		r17,  0x003c(r30)
	lwz		r18,  0x0f2c(r1)
	slwi	r18, r18,  3
	addc	r17, r17, r18



;	                     TimerFire7                      

TimerFire7	;	OUTSIDE REFERER
	addze	r16, r16
	stw		r16,  0x0038(r30)
	stw		r17,  0x003c(r30)
	mtxer	r19
	mr		r8, r30
	bl		EnqueueTimer
	b		TimerDispatch_0x144



;	                     major_0x134d8                      

;	Dead code -- probably removed from TimerTable

	lwz		r18, PSA.DecClockRateHzCopy(r1)
	lwz		r19,  0x0f88(r1)
	subf.	r19, r18, r19
	ble		TimerFire8_0x1c
	srwi	r19, r19, 11
	mfxer	r20

major_0x134d8_0x18
	mftbu	r16
	mftb	r17,  0x10c
	mftbu	r18
	cmpw	r16, r18
	li		r18,  0x00
	bne-	major_0x134d8_0x18
	mttb	r18
	addc	r17, r17, r19
	addze	r16, r16
	mttbu	r16
	mttb	r17
	lwz		r18, PSA.DecClockRateHzCopy(r1)
	srwi	r18, r18, 11



;	                     TimerFire8                      

TimerFire8	;	OUTSIDE REFERER
	addc	r17, r17, r18
	addze	r16, r16
	stw		r16,  0x0038(r30)
	stw		r17,  0x003c(r30)
	mtxer	r20
	mr		r8, r30
	bl		EnqueueTimer

TimerFire8_0x1c	;	OUTSIDE REFERER
	b		TimerDispatch_0x144



;	                     major_0x13544                      

;	Dead code -- probably removed from TimerTable

	lwz		r19, PSA._36c(r1)
	mfxer	r20
	cmpwi	cr1, r19,  0x00
	srawi	r8, r19, 31
	beq		cr1, TimerFire6_0x4

major_0x13544_0x14
	mftbu	r16
	mftb	r17,  0x10c
	mftbu	r18
	cmpw	r16, r18
	li		r18,  0x00
	bne-	major_0x13544_0x14
	mttb	r18
	addc	r19, r17, r19
	adde	r18, r16, r8
	mttbu	r18
	mttb	r19
	bgt		cr1, major_0x13544_0x64

major_0x13544_0x44
	mftbu	r18
	mftb	r19,  0x10c
	mftbu	r8
	cmpw	r18, r8
	bne-	major_0x13544_0x44
	subfc	r19, r17, r19
	subfe.	r18, r16, r18
	blt		major_0x13544_0x44

major_0x13544_0x64
	lwz		r18, PSA._368(r1)
	addc	r17, r17, r18
	addze	r16, r16
	stw		r16,  0x0038(r30)



;	                     TimerFire6                      

TimerFire6	;	OUTSIDE REFERER
	stw		r17,  0x003c(r30)

TimerFire6_0x4	;	OUTSIDE REFERER
	mtxer	r20
	beq		cr1, TimerDispatch_0x144
	mr		r8, r30
	bl		EnqueueTimer
	b		TimerDispatch_0x144



;	                     major_0x135d0                      

;	Dead code -- probably removed from TimerTable

	mfxer	r19
	lwz		r16,  0x0038(r30)
	lwz		r17,  0x003c(r30)
	lwz		r18,  0x0f2c(r1)
	srwi	r18, r18,  1
	addc	r17, r17, r18
	addze	r16, r16
	stw		r16,  0x0038(r30)
	stw		r17,  0x003c(r30)
	mtxer	r19
	mr		r8, r30
	bl		EnqueueTimer
	bl		getchar
	cmpwi	r8, -0x01
	beq		TimerDispatch_0x144
	bl		panic_non_interactive
	b		TimerDispatch_0x144



;	ARG		Timer *r8
;	CLOB	r16-r20

EnqueueTimer	;	OUTSIDE REFERER

	;	Keep the trip-time of this timer in r16/r17
	lwz		r16, Timer.Time(r8)
	lwz		r17, Timer.Time+4(r8)

	;	r20 = timer being considered
	;	r18/r19 = trip-time of timer being condidered
	lwz     r20, PSA.TimerQueue + TimerQueueStruct.LLL + LLL.Next(r1)
	lwz		r18, Timer.Time(r20)
	lwz		r19, Timer.Time+4(r20)

	;	First try to insert at head of global TMRQ
	cmpw	r16, r18
	cmplw	cr1, r17, r19
	bgt		@insert_further_ahead
	blt		@insert_at_tail
	bge		cr1, @insert_further_ahead

@insert_at_tail
	addi	r20, r1, PSA.TimerQueue + TimerQueueStruct.LLL

	li		r18, 1
	stb		r18, Timer.Byte3(r8)

	;	Insert at the very back of the queue
	lwz		r19, LLL.Freeform(r8)
	lwz		r9, LLL.Freeform(r20)
	stw		r9, LLL.Freeform(r8)				;	my freeform = considered freeform
	lwz		r9, LLL.Next(r20)
	stw		r9, LLL.Next(r8)					;	my next = next of considered
	stw		r20, LLL.Prev(r8)					;	my prev = considered
	stw		r8, LLL.Prev(r9)					;	prev of next of considered = me
	stw		r8, LLL.Next(r20)					;	next of considered = me
	stw		r19, LLL.Freeform(r8)				;	my freeform = my original freeform

	b		SetTimeslice

@insert_further_ahead
	lwz		r20, PSA.TimerQueue + TimerQueueStruct.LLL + LLL.Prev(r1)

@searchloop
	lwz		r18, Timer.Time(r20)
	lwz		r19, Timer.Time+4(r20)
	cmpw	r16, r18
	cmplw	cr1, r17, r19
	bgt		@insert_after_this_one
	blt		@next
	bge		cr1, @insert_after_this_one

@next
	lwz		r20, LLL.Prev(r20)
	b		@searchloop

@insert_after_this_one
	li		r18, 1
	stb		r18, Timer.Byte3(r8)

	lwz		r19, LLL.Freeform(r8)
	lwz		r9, LLL.Freeform(r20)
	stw		r9, LLL.Freeform(r8)				;	my freeform = considered freeform
	lwz		r9, LLL.Next(r20)
	stw		r9, LLL.Next(r8)					;	my next = next of considered
	stw		r20, LLL.Prev(r8)					;	my prev = considered
	stw		r8, LLL.Prev(r9)					;	prev of next of considered = me
	stw		r8, LLL.Next(r20)					;	next of considered = me
	stw		r19, LLL.Freeform(r8)				;	my freeform = my original freeform

	blr



;	Remove a Timer from the global timer firing queue (TMRQ).
;	If the Timer was to be the next to fire, then perform the
;	standard decrementer rollover adjustment.

;	ARG		Timer *r8

DequeueTimer
	lwz		r16, Timer.QueueLLL + LLL.FreeForm(r8)
	cmpwi	r16, 0
	lwz		r18, PSA.TimerQueue + TimerQueueStruct.LLL + LLL.Next(r1)
	beq		Local_Panic

	RemoveFromList		r8, scratch1=r16, scratch2=r17

	li		r16, 0
	cmpw	r18, r8
	stb		r16, Timer.Byte3(r8)

	beq		SetTimeslice

	blr



;	Get the number of timebase ticks in a specified period

;	ARG		long r8 period (positive for ms, negative for us)

TimebaseTicksPerPeriod
	mr.		r17, r8
	li		r19, 250
	lwz		r9, KDP.ProcessorInfo + NKProcessorInfo.DecClockRateHz(r1)

	bgt+	@period_positive
	blt+	@period_negative
	li		r8, 0
	li		r9, 0
	blr						;	fail
@period_negative
	neg		r17, r17
	lisori	r19, 250000
@period_positive

	divw	r19, r9, r19

	mullw	r9, r19, r17
	mulhw	r8, r19, r17

	srwi	r9, r9, 2
	rlwimi	r9, r8, 30, 0, 1
	srwi	r8, r8, 2

	blr




;	RET		long r8 tbu, long r9 tbl
;	CLOB	r16, r17

GetTime

	mfpvr	r8
	rlwinm.	r8, r8, 0, 0, 14
	beq		@is_601

@retry_timebase:
	mftbu	r8
	mftb	r9
	mftbu	r16
	cmpw	r8, r16
	bne-	@retry_timebase

	b		@return

@is_601
	dialect	POWER		;	disassembled this in POWER mode!
	
@retry_rtc
	mfrtcu	r8
	mfrtcl	r9
	mfrtcu	r16
	cmp		0, r8, r16

	dialect	PowerPC
	bne-	@retry_rtc		;	POWER chokes on hints?
	dialect	POWER

	liu		r16, 1000000000 >> 16
	oril	r16, r16, 1000000000 & 0xffff

	mfmq	r17
	mul		r8, r16, r8
	mfmq	r16
	mtmq	r17
	
	mfxer	r17
	a		r9, r16, r9
	aze		r8, r8
	mtxer	r17

	dialect POWERPC

@return
	blr
