mac-rom/OS/VerticalRetraceMgr.a

460 lines
17 KiB
Plaintext

;
; File: VerticalRetraceMgr.a
;
; Contains: This file contains the core routines pertaining to the vertical
; retrace manager. VINSTALL installs a routine into the vertical
; retrace task list while VREMOVE removes it.
;
; Written by: Andy Hertzfeld 05-May-81
;
; Copyright: © 1981-1993 by Apple Computer, Inc., all rights reserved.
;
; Change History (most recent first):
;
; <SM6> 11/9/93 KW added some eieioSTP macros. Only expands for CygnusX1 ROM
; <SM5> 1/29/93 RB Made the PseudoVBLInt routine compatible with NuKernel by
; changing the way it uses the status register.
; <SM4> 9/10/92 AEK Other half of pseudo-VBL support, add code to re-arm timemgr task
; <SM3> 5/21/92 kc Append "Trap" to the names of Enqueue and Dequeue to avoid name
; conflict with the glue.
; <6> 5/6/92 JSM Get rid of conditionals: hasSlotMgr is always true, Cpu is
; always ³ 020 since this file is only used in ROM builds. This
; file now has no conditionals.
; <5> 10/1/91 JSM DonÕt use hasADB conditional, all future ROMs will support ADB.
; <4> 9/10/91 JSM Cleanup header.
; <2> 6/12/91 LN Changed #include 'HardwareEqu.a' to 'HardwarePrivateEqu.a'
; <1.4> 4/16/89 GGD Rewritten so that SlotVBLs can share code with classic VBL
; handling. Changed slot handling to use shared data structures
; with slot interrupt handler. Increased data structures to
; support slots $0É$E, to allow for expansion chassis.
; <1.3> 3/6/89 GGD moved VBL and SlotVBL interrupt handlers to VerticalRetraceMgr.a
; from InterruptHandlers.a Modified 60hz handler to not re-enable
; interrupts if it was interrupting a vbl task, to prevent
; potential excessive stack growth if other level 1 interrupts are
; consuming a lot of time. Deleted obsolete unreferenced exported
; label CoreStub. Eliminated unused include files.
; <1.2> 2/20/89 rwh changed to feature based conditionals.
; <1.1> 11/10/88 CCH Fixed Header.
; <1.0> 11/9/88 CCH Adding to EASE.
; <1.2> 10/24/88 djw Modified InitVBLQs to alloc space for all supported NuBus slots
; (internal and bus expansion). Modified ChkSlot to support slot
; zero and bus expansion slots.
; <¥1.1> 9/23/88 CCH Got rid of inc.sum.d and empty nFiles
; <1.0> 2/10/88 BBM Adding file for the first time into EASEÉ
; <C914> 10/29/87 rwh Port to Modern Victorian. Changed Via2IntMask to SlotIntMask to
; make things more general
; <C913> 10/16/87 MSH Added nHardwareEqu.a to INCLUDEs
; <C755> 2/4/87 RDC Cleanup error return codes in AttachVBL and DoVBLTask routines
; <C665> 1/22/87 RDC Code review cleanup
; <C582> 1/2/87 RDC Misc cleanup
; <C572> 12/30/86 RDC Changed various equate names due to changes by GWN in equate
; file
; <A327> 11/2/86 RDC Finally added a copyright notice!
; <C224> 10/15/86 RDC Add error checking code for invalid slot #'s
; <C206> 10/9/86 bbm Modified to mpw aincludes.
; <C147> 9/8/86 RDC Added routines to support NuMac slot VBL queues
; 7/24/85 RDC Changed interrupt level masking to use equates Added separate
; include statement for HWequ file (no longer in systlqk.sym)
; 5/7/85 JTC Disallow VBL interrupts during computation. <07May85>
; 4/30/85 JTC Fix overflow problem in computing initial phase bias. <30Apr85>
; 1/30/85 LAK Added RAM patch to VInstall.
; 1/23/85 LAK Adapted for new equate files.
; 8/8/83 LAK added a comment only.
; 6/18/83 AJH saved 2 bytes by moving CoreStub
; 7/26/82 LAK phase of zero specifies no offset (used for exact one shots) -
; mod to VINSTALL
; 6/4/82 LAK use phase in VINSTALL to determine initial count
; 9/17/81 bmw vinstall returns zero in d0 if it's happy
;
print off
LOAD 'StandardEqu.d'
include 'HardwarePrivateEqu.a'
include 'SlotMgrEqu.a'
print on
print nomdir
machine mc68020
VBLCore proc export
export VInstall,VRemove,VBLInt,PseudoVblInt
import EnqueueTrap,DequeueTrap
export InitVBLQs,SlotVInstall,SlotVRemove
export AttachVBL,DoVBLTask
;_______________________________________________________________________
;
; Trap: _VINSTALL bb40
;
; Arguments: A0 (input) : address of vertical retrace control block
; D0 (output): error code - 0 no error
; -2 invalid queue element type
;
; Function: Installs a vertical retrace routine which is called after
; VBLCOUNT(A0) video frames.
; To permit VBl tasks to be called with the same frequencies but <30Apr85>
; in different time slices the following phasing mechanism is used:
; Compute T := Ticks MOD Count (this takes two DIVU's to avoid overflow).
; Then T indicates the momentary phase, relative to Count.
; Then compute the proper InitialCount so that the VBl task will be
; executed Phase slices AFTER the next slice whose MOD with Count is 0.
; if (Phase - T) >= 0
; then InitialCount := Count + (Phase - T)
; else InitialCount := Count + (Count + (Phase - T))
; To compute Ticks MOD Count we let Ticks = 2^16*Thi + Tlo and note that
; Ticks MOD Count = ( 2^16*(Thi MOD Count) + Tlo ) MOD Count
; with the pleasant benefit that neither MOD cannot cause DIVU to overflow!
;
; However, life is not without its uncertainties! If the clock should tick
; whilest this computation is performed, the initial phase will be off by
; a tick. But this could be solved by INSTALLING such tasks at VBL time,
; guaranteeing a fresh slice within which to work!!!
;
; Registers Used: D0,D1,D2,A0,A1 <30Apr85>
;_______________________________________________________________________
VInstall
lea VBLQueue+2,a1
@loop move.l (a1),d1
beq.s @dontflunk
move.l d1,a1
cmp.l a0,a1
bne.s @loop
moveq.l #0,d0
rts
@dontflunk lea VBLQueue,a1 ; get address of queue <1.4>
VInstallCommon ; common code shared with SlotVInstall
cmpi.w #vType,VBLType(a0) ; is it the proper type?
bne.s VTypeError ; if not, exit with error <1.4>
move.w vblCount(a0),d1 ; D1.W = Count <30Apr85>
beq.s @QueueIt ; Count=0 is special, one-shot case <30Apr85>
tst.w VBLPhase(a0) ; zero phase is also special <C204>
beq.s @QueueIt ; queue up for count ticks later <C204>
move.w sr,-(sp) ; save current interrupt status <07May85>
ori.w #HiIntMask,sr ; disallow VBL interrupts <07May85>/<24Jul85>
move.l Ticks-VBLQueue(a1),d0; D0 = 2^16*Thi + Tlo <30Apr85>
swap d0 ; <30Apr85>
moveq.l #0,d2 ; <30Apr85>
move.w d0,d2 ; D2 = Thi <30Apr85>
divu d1,d2 ; D2.hi = Thi MOD Count <30Apr85>
swap d2 ; <30Apr85>
move.w d2,d0 ; <30Apr85>
swap d0 ; D0 = 2^16*(Thi MOD Count) + Tlo <30Apr85>
divu d1,d0 ; <30Apr85>
swap d0 ; D0.W = Ticks MOD Count <30Apr85>
sub.w VBLPhase(a0),d0 ; <30Apr85>
neg.w d0 ; D0.W = Phase - (Ticks MOD Count) <30Apr85>
bpl.s @PhaseDone ; <30Apr85>
add.w d1,d0 ; D0.W = Count + (Phase - (...)) <30Apr85>
@PhaseDone ; <30Apr85>
add.w d0,vblCount(a0) ; <30Apr85>
move.w (sp)+,sr ; restore old status <07May85>
@QueueIt jsr EnqueueTrap ; install it in the queue
moveq.l #noErr,D0 ; indicate success
rts ; and return...
VTypeError moveq.l #VTypErr,d0 ; flag the error
rts ; and return...
;_______________________________________________________________________
;
; The VREMOVE bba2 trap routine removes a vertical retrace control block from the
; VBL queue. On entry, A0 points to the control block. D0 returns the error
; code; all other registers are preserved.
;
;_______________________________________________________________________
;
VRemove cmpi.w #vType,VBLType(a0) ; is it the proper type?
bne.s VTypeError ; if not, exit with error
move.l a1,-(sp) ; preserve A1
lea VBLQueue,a1 ; get address of queue
jsr DequeueTrap ; remove it from the queue
movea.l (sp)+,a1 ; restore A1
AnRTS rts ; return Dequeue error code
;_______________________________________________________________________ <1.3>
;
; we put the code for the VBL interrupt handler next bbb8
;
; NOTE: This handler expects that the interrupt is still pending, and clears
; it by clearing the CA1 interrupt flag on VIA 1 (base address passed
; in register A1). On OSS based machines, this is not quite the case,
; A1 is setup to point to OSS60HzAck-VIFR, so that when the write to
; VIFR(A1) is done, it will actually write to OSS60HzAck. Be Carefull!
;
;_______________________________________________________________________
;
; Fake time manager VBL interrupts enter here
;
PseudoVBLInt
movea.l a1, a0
move.l #-16626,d0 ; 60.15 Hz
movea.l jPrimeTime, a1
jsr (a1) ; restart time manager task
bra.s BumpTicks
VBLInt
eieioSTP
move.b #1<<ifCA1,vIFR(a1) ; clear and re-enable vertical retrace interrupts
nop
eieioSTP
BumpTicks
addq.l #1,Ticks ; bump tick count
bset.b #inVBL,qFlags+VBLQueue ; already in the VBL mgr?
bne.s AnRTS ; if so, skip it this time
ANDI.W #$F8FF,SR ; open up interrupts <1.3> <SM5> rb
; We call the cursor task every vertical retrace and the keyboard and mouse
; button tasks every other one, so these calls are just "hardwired" in.
move.l StkLowPt,d0
beq.s @StackOk
cmpa.l d0,sp ; new low?
bhs.s @CheckStack
move.l sp,StkLowPt ; new low in stack movement
@CheckStack movea.l ApplZone,a1
cmpa.l BkLim(a1),sp
bhs.s @StackOk ; br if no crash (always another time)
moveq.l #dsStknHeap,d0
_SysError ; it may already be too late . .
@StackOk
; now we service the VBL queue . . .
lea VBLQueue,a1 ; A1 points to the queue
RunVBLs lea qHead-vblink(a1),a0 ; setup to fetch head of list
@VBLloop move.l vblink(a0),d0 ; advance to next block
beq.s @VBLDone ; if queue is empty, exit
; Here we update the counter in the vertical retrace control block and
; call the appropriate routine when it times out. A0 points to the current
; block.
movea.l d0,a0 ; get pointer to next VBL control block
subq.w #1,vblCount(a0) ; decrement the counter
bne.s @VBLloop ; if non-zero, don't bother
move.l a0,-(sp) ; preserve A0 (pointer to VBL ctl block)
move.l a1,-(sp) ; preserve queue header pointer
movea.l vblAddr(a0),a1 ; get address of service routine
jsr (a1) ; call the routine with A0 pointing to the block
movea.L (sp)+,a1 ; restore A1
movea.L (sp)+,a0 ; restore A0
tst.w vblCount(A0) ; did the routine reset count?
bne.s @VBLloop ; if not, leave it in the queue
; unlink the element since it timed out
jsr DequeueTrap ; unlink it
bra.s @VBLloop ; and search the rest of the queue
@VBLDone bclr.b #inVbl,qFlags(a1) ; remember that we're done!
* moveq.l #noErr,d0 ; no error (d0=0 from code at @VBLloop)
rts ; return with success
;_______________________________________________________________________
;
; The following routines handle slot VBL tasks for the NuBus system
;_______________________________________________________________________
with slotVBLInfo
; In order to share code, we take advantage of structure of the low memory
; variables associated with the classic VBL manager, and group the queue
; header and tick count in the same way for slots.
_AssumeEq slotTickCount-slotVBLQHdr,Ticks-VBLQueue
;_______________________________________________________________________
;
; Routine: GetSlotVBLQHdr bc2e
;
; Arguments: D0 (input) : video card slot ($0..$E possible)
; D0 (output): error code
; A1 (output): address of SlotVBLQHdr for requested slot
;
; Function: Utility routine to do check for valid slot number, and return
; the address of the associated slot VBL queue header.
; If the slot number is out of range, an error code will be
; returned, and the routine will return to the callers caller,
; instead of directly to the caller.
;
; Called by: SlotVInstall, SlotVRemove, AttachVBL, DoVBLTask
;
; Registers Used: D0,A1
;_______________________________________________________________________
with slotIntGlobals
GetSlotVBLQHdr
ext.w d0 ; ignore high byte
cmpi.w #sLastSlot,d0 ; check for valid slot #
bhi.s @slotTooBig ; return error if too big
movea.l ([SlotQDT],d0.w*4,slotVBLPtrs),a1 ; point to the VBL queue header
@return
rts ; return with success
@slotTooBig
move.l ([$2b6],$260),a1
move.l a1,d1
beq.s @skipthis
move.l (a1),d1
beq.s @skipthis
movem.l d0/d2/a0,-(sp)
sub.l a0,a0
move.l d1,a1
move.l #'vbl ',d1
jsr (a1)
move.l a0,a1
movem.l (sp)+,d0/d2/a0
move.l a1,d1
bne.s @return
@skipthis
addq.w #4,sp ; pop the return address
move.w #smSlotOOBErr,d0 ; return with slot # error
rts ; return to callers caller
endwith
;_______________________________________________________________________
;
; Trap: _SlotVINSTALL bc70
;
; Arguments: A0 (input) : address of vertical retrace control block
; D0 (input) : video card slot ($0..$E possible) <v1.2>
; D0 (output): error code - 0 no error
; -2 invalid queue element type
; -360 invalid slot #
;
; Function: Installs a slot specific vertical retrace routine which is
; called after VBLCOUNT(A0) video frames. The count is treated
; as being in units of the slot's VBL time (e.g. 1/67th sec for
; the standard system monitor). Phase parameter is treated in
; same way as for Mac+ VBL tasks with substitution of a "slot
; tickcount" in place of the global TICKS value.
;
; Registers Used: D0,D1,D2,A0,A1
;_______________________________________________________________________
SlotVInstall
bsr.s GetSlotVBLQHdr ; find the VBL Queue for the slot
bra VInstallCommon ; install the slot VBL handler
;_______________________________________________________________________
;
; Trap: _SlotVRemove bc76
;
; Arguments: A0 (input) : address of vertical retrace control block
; D0 (input) : video card slot ($0..$E possible) <v1.2>
; D0 (output): error code - 0 no error
; -2 invalid queue element type
;
; Function: Removes a slot specific vertical retrace control block from the
; slot's VBL queue.
;
; Registers Used: D0,D1,A1
;_______________________________________________________________________
SlotVRemove bsr.s GetSlotVBLQHdr ; find the VBL Queue for the slot
cmpi.w #vType,VBLType(a0) ; is it the proper type?
bne VTypeError ; if not, exit with error
jmp DequeueTrap ; remove it from the queue, and return
;_______________________________________________________________________
;
; Trap: _AttachVBL bc86
;
; Arguments: D0 (input) : new video card slot for system VBL ($0..$E possible) <v1.2>
; D0 (output): error code
;
; Function: Does setup of ptr in slot VBL table to main system VBL queue.
;
; Registers Used: D0,D1,A1
;_______________________________________________________________________
AttachVBL bsr.s GetSlotVBLQHdr ; find the VBL Queue for the slot
move.l a1,ScrnVBLptr ; save new screen VBL ptr
moveq.l #noErr,d0 ; no error
rts ; and return with success
;_______________________________________________________________________
;
; Trap: _DoVBLTask bc90
;
; Arguments: D0 (input) : video card slot ($0..$E possible) <v1.2>
; D0 (output): error code
;
; Function: Triggers servicing of slot specific VBL queue.
;
; Registers Used: D0,D1,A1
;_______________________________________________________________________
DoVBLTask bsr.s GetSlotVBLQHdr ; find the VBL Queue for the slot
; first update the slot's "tickcount"
addq.l #1,slotTickCount-slotVBLQHdr(A1) ; increment slot tickcount
; check if main system queue being serviced
cmpa.l ScrnVBLPtr,a1 ; is it the main screen?
bne.s @cursorDone ; skip if not
move.l JCrsrTask,d0 ; else call the cursor task
beq.s @cursorDone ; if there is one installed
movea.l d0,a0 ; there is - go do it
move.l a1,-(sp) ; save queue header ptr
jsr (a0) ; run the cursor task
movea.l (sp)+,a1 ; restore queue ptr
@cursorDone
; now we service the VBL queue . . .
bra RunVBLs ; run the VBL tasks, return with success
endwith
;_______________________________________________________________________
;
; Routine: InitVBLQs bcae
;
; Arguments: none
;
; Function: Initializes the variables related to Slot VBL's.
;
; Registers Used: A0
;_______________________________________________________________________
InitVBLQs LEA.L DoVBLTask,A0 ; and save hook to
MOVE.L A0,JVBLTask ; VBL task execute routine
CLR.L ScrnVBLPtr ; init main screen ptr save global
RTS ; exit to caller
end