supermario/base/SuperMarioProj.1994-02-09/OS/TimeMgr/TimeMgrPatch.a
2019-06-29 23:17:50 +08:00

267 lines
11 KiB
Plaintext

;
; File: TimeMgrPatch.a
;
; Contains: code to patch in a new version of the Time Mgr. for various machines
;
; Written by: Darin Adler
;
; Copyright: © 1990-1992 by Apple Computer, Inc., all rights reserved.
;
; Change History (most recent first):
;
; <4> 2/12/92 JSM Moved this file to TimeMgr folder, keeping all the old
; revisions.
; <3> 9/9/91 JSM Cleanup header.
; <2> 12/8/90 dba <gbm> turn off Time Mgr. patches for A/UX
; <1> 9/22/90 dba Created today. Contains a complete patch of TimeMgr for Plus,
; SE, and II ROMs, and a patch for the Portable and IIci ROMs that
; adds the _Microseconds trap.
;
load 'StandardEqu.d'
include 'HardwarePrivateEqu.a'
include 'LinkedPatchMacros.a'
AfterFreezeTimeInRmvTime ROMBind (Portable,$5EC8),(IIci,$AE96)
MultAndMerge ROMBind (Portable,$5F34),(IIci,$AF02)
AfterFreezeTimeInPrimeTime ROMBind (Portable,$5F9A),(IIci,$AF3E)
AfterFreezeTimeInTimer2Int ROMBind (Portable,$6090),(IIci,$B02E)
OldTimeMgrGlobalsSize equ 16
; globals in system heap (same RECORD in TimeMgr.a; move it to an equate file if you like)
TimeMgrPrivate record 0,increment ; time manager private storage
ActivePtr ds.l 1 ; pointer to soonest active request
TimerAdjust ds.b 1 ; number of VIA ticks used loading timer
TimerLowSave ds.b 1 ; low byte of VIA timer from last FreezeTime <4>
RetryAdjust ds.w 1 ; number of via ticks for underflow retry
CurrentTime ds.l 1 ; number of virtual ticks since boot
BackLog ds.l 1 ; number of virtual ticks of ready tasks
**** NOTE: The ordering of the following 4 fields must not change (FreezeTime Depends on it) <4>
HighUSecs ds.l 1 ; high 32 bits of microsecond count <4>
LowUSecs ds.l 1 ; low 32 bits of microsecond count <4>
FractUSecs ds.w 1 ; 16 bit fractional microsecond count <4>
CurTimeThresh ds.w 1 ; CurrentTime threshold for updating µsec count <4>
**** end of order dependent fields <4>
PrivateSize equ *-TimeMgrPrivate ; size of this record
endr
TITLE 'Time Manager - Equates'
TaskActiveBit equ 7 ; high bit of QType word is active flag
ExtendedTmTaskBit equ 6 ; indicates an extended TmTask record
T2IntBit equ 5 ; VIER/VIFR bit num for VIA Timer 2
;_______________________________________________________________________
;
; Representations of time in the Time Manager.
;
; Time is represented externally in two ways, both are stored in a longword,
; if the value is positive, it represents milliseconds, and if it is
; negative, it represents negated microseconds. This representation is used
; as the delay time input to PrimeTime, and as the unused remaining time
; output by RmvTime.
;
; The VIA1 Timer2 is the 16 bit hardware timer used by the time manager.
; On all current machines, it decrements at a rate of 783360 Hz, and
; generates an interrupt, and keeps counting, when it counts through zero.
; This provides resolution of 1.276 µsec, and a range of 83.660 msec.
;
; Internally the time manager represents time as a virtual unsigned 36 bit
; VIA timer, which gives a range of about 1 day. However, since we only
; have 32 bits to store time in, we drop the low 4 bits of the timer,
; which reduces the resolution by a factor of 16 to 20.425 µsec.
;
; Converting between the external and internal forms of time is done by
; multiplying by the proper fixed point constants, and shifting the binary
; point of the 64 bit result to get just the integer portion of the result.
; The computation of the 32 bit conversion constants requires 64 bit
; intermediate results, and unfortunatly the assembler only provides 32
; bit expression evaluation, so the proper constants were computed with
; a 64 bit hex caculator, and hard coded here (yuck!). These are not
; "Magic Numbers", the formula for computing them is provided, so that
; they may be re-computed if any of the parameters ever change.
;
;_______________________________________________________________________
TicksPerSec equ 783360 ; VIA Timer clock rate
TickScale equ 4 ; Internal time is VIA ticks >> TickScale
MsToIntFractBits equ 26 ; number of fraction bits in 64 bit result
*MsToInternal equ ((TicksPerSec<<(MsToIntFractBits-TickScale))\
+999)/1000
MsToInternal equ $C3D70A3E ; msec to internal time multiplier
UsToIntFractBits equ 32 ; number of fraction bits in 64 bit result
*UsToInternal equ ((TicksPerSec<<(UsToIntFractBits-TickScale))\
+999999)/1000000
UsToInternal equ $0C88A47F ; µsec to internal time multiplier
IntToMsFractBits equ 32 ; number of fraction bits in 64 bit result
*InternalToMs equ ((1000<<(IntToMsFractBits+TickScale))\
+TicksPerSec-1)/TicksPerSec
InternalToMs equ $053A8FE6 ; internal time to msec multiplier
IntToUsFractBits equ 27 ; number of fraction bits in 64 bit result
*InternalToUs equ ((1000000<<(IntToUsFractBits+TickScale))\
+TicksPerSec-1)/TicksPerSec
InternalToUs equ $A36610BC ; internal time to µsec multiplier
macro ; Macro for interfacing with the MultAndMerge routine.
Convert &Multiplier,&FractionBits
jsrROM MultAndMerge ; input/output is D0
dc.l &Multiplier ; conversion multiplier
if &eval(&FractionBits)=32 then
dc.l 0 ; merge mask (low 32 bits all fraction)
else
dc.l -1<<&FractionBits ; merge mask (some low bits not fraction)
rol.l #32-&FractionBits,d0 ; position result after merge
endif
endm
;————————————————————————————————————————————————————————————————————————————————————————————————————
GetRidOfPowerMgrInFreezeTime InstallProc (Plus,SE,II,IIci,notAUX)
import PoundThreeNOPsHereIfNoPowerMgr
lea PoundThreeNOPsHereIfNoPowerMgr,a0
move.w #$4E71,d0 ; get the NOP opcode
move.w d0,(a0)+ ; NOP
move.w d0,(a0)+ ; NOP
move.w d0,(a0)+ ; NOP
rts
EndProc
InstallTimeMgrPlusSEII InstallProc (Plus,SE,II,notAUX)
import InitTimeMgr
move.w sr,-(sp) ; save interrupt level
ori.w #$0700,sr ; no interrupts while swapping Time Mgrs
leaResident __InsTime,a0
moveq #$58,d0 ; _InsTime
_SetTrapAddress newOS
leaResident __RmvTime,a0
moveq #$59,d0 ; _RmvTime
_SetTrapAddress newOS
leaResident __PrimeTime,a0
moveq #$5A,d0 ; _PrimeTime
_SetTrapAddress newOS
leaResident __Microseconds,a0
moveq #$93-$100,d0 ; SetTrapAddress(os) only looks at the low byte
_SetTrapAddress newOS
movea.l TimeVars,a0 ; get pointer to time manager globals
movea.l MSQueue+qHead(a0),a1 ; save header of queue
_DisposPtr ; dispose the old globals
jsr InitTimeMgr ; initialize the new TimeMgr (trashes no registers)
@loop
move.l a1,d0 ; test for end of list
beq.s @done ; exit when queue empty
move.l a1,a0 ; setup a0 for _PrimeTIme
move.l qLink(a0),a1 ; remember queue successor
move.l tmCount(a0),d1 ; save time remaining for _PrimeTime
_InsTime ; re-install the time manager task
move.l d1,d0 ; pass time remaining to _PrimeTime
beq.s @loop ; if not running, don't prime it
_PrimeTime ; restart the timer with new time mgr
bra.s @loop ; loop through entire queue
@done
move.w (sp)+,sr ; restore interrupt level
rts
EndProc
InstallTimeMgrPortableIIci InstallProc (Portable,IIci,notAUX)
move.w sr,-(sp) ; save interrupt level
ori.w #$0700,sr ; no interrupts while swapping Time Mgrs
leaResident RmvTimeNewFreezeTime,a0
moveq #$59,d0 ; _RmvTime
_SetTrapAddress newOS
leaResident PrimeTimeNewFreezeTime,a0
moveq #$5A,d0 ; _PrimeTime
_SetTrapAddress newOS
leaResident Timer2IntNewFreezeTime,a0
move.l a0,Lvl1DT+(T2IntBit*4) ; put into interrupt table
leaResident __Microseconds,a0
moveq #$93-$100,d0 ; SetTrapAddress(os) only looks at the low byte
_SetTrapAddress newOS
moveq #TimeMgrPrivate.PrivateSize,d0
_NewPtr sys,clear ; allocate and clear the structure
move.l a0,a1 ; keep the pointer for reference
move.l TimeVars,a0 ; get the old globals
moveq #OldTimeMgrGlobalsSize,d0
_BlockMove ; copy over the ones we care about
_DisposPtr ; get rid of the old globals
move.l a1,TimeVars ; point to the new globals
move.w (sp)+,sr ; restore interrupt level
rts
EndProc
;————————————————————————————————————————————————————————————————————————————————————————————————————
; patch to RmvTime that calls our copy of FreezeTime, and then rejoins the ROM
RmvTimeNewFreezeTime proc export
import FreezeTime
move.l d3,-(sp) ; save d3 also
jsr FreezeTime ; setup to manipulate time queue
jmpROM AfterFreezeTimeInRmvTime ; rejoin the ROM
endproc
;————————————————————————————————————————————————————————————————————————————————————————————————————
; patch to PrimeTime that calls our copy of FreezeTime, and then rejoins the ROM
PrimeTimeNewFreezeTime proc export
import FreezeTime
move.l d3,-(sp) ; save d3 also
tst.l d0 ; see if +msec or -µsec
bpl.s @msec ; µsec are negated, msec pos
@usec neg.l d0 ; get positive number of µsecs
convert UsToInternal,UsToIntFractBits ; convert µsec to internal
bra.s @ConvertDone ; join common code
@msec convert MsToInternal,MsToIntFractBits ; convert msec to internal
@ConvertDone
jsr FreezeTime ; setup to manipulate time queue
jmpROM AfterFreezeTimeInPrimeTime ; rejoin the ROM
endproc
;————————————————————————————————————————————————————————————————————————————————————————————————————
; patch to Timer2Int that calls our copy of Timer2Int, and then rejoins the ROM
Timer2IntNewFreezeTime proc export
import FreezeTime
jsr FreezeTime ; stop the timer, adjust time remaining
jmpROM AfterFreezeTimeInTimer2Int ; rejoin the ROM
;————————————————————————————————————————————————————————————————————————————————————————————————————
End