mirror of
https://github.com/elliotnunn/sys7.1-doc-wip.git
synced 2024-12-14 02:30:24 +00:00
1551 lines
52 KiB
Plaintext
1551 lines
52 KiB
Plaintext
|
;
|
||
|
; File: RBVDriver.a
|
||
|
;
|
||
|
; Contains: The Mac OS Video Driver code that supports RBV-based built-in video
|
||
|
; systems.
|
||
|
;
|
||
|
; Written by: David Fung
|
||
|
;
|
||
|
; Copyright: © 1987-1992 by Apple Computer, Inc. All rights reserved.
|
||
|
;
|
||
|
; Change History (most recent first):
|
||
|
;
|
||
|
; <SM3> 11/5/92 SWC Changed VideoEqu.a->Video.a and ShutdownEqu.a->Shutdown.a.
|
||
|
; <SM2> 11/2/92 kc Don't include SonicEqu.a.
|
||
|
; <1> 10/6/92 GDW New location for ROMLink tool.
|
||
|
; <SM3> 09-03-92 jmp (jmp,H2) Corrected .s vs. non-.s branches and odd-alignment
|
||
|
; problems.
|
||
|
; <SM2> 5/16/92 kc Roll in Horror Changes. Comments follow:
|
||
|
; <T2> 12/11/90 HJR Integration of Tim and V8 Video into the Terror Project.
|
||
|
; <T7> 6/12/90 JJ Add support for Elsie Apple II emulation video modes.
|
||
|
; <T6> 4/30/90 JJ Minor formatting changes.
|
||
|
; <H4> 4/3/90 CV Moved the search string to find the video driver overpatch to
|
||
|
; 'DeclDataRBV.a'.
|
||
|
; <H3> 3/13/90 CV Improving Erickson overpatch version of the driver.
|
||
|
; Added prime routine which finishes up install of overpatch
|
||
|
; RBVDriver.
|
||
|
; <5> 9/18/91 JSM Cleanup header.
|
||
|
; <4> 4/3/90 DF Moved GDFlags bit flag equates to RBVDepVideoEqu.a where they
|
||
|
; are shared by ElsieDriver.a
|
||
|
; <3> 2/14/90 DAF Changed Open routine to remove dependency on Is16MHz flag word
|
||
|
; <2> 2/13/90 DAF Corrected interrupt level changing code for Erickson.
|
||
|
; 2/13/90 DAF Corrected interrupt level changing code for Erickson.
|
||
|
; <2.0> 7/11/89 DAF FOR AURORA BUILD - Minor code review changes in Open
|
||
|
; 7/11/89 DAF Incorporated code review changes. Added flag detection of
|
||
|
; non-16MHz machines.
|
||
|
; <1.9> 6/30/89 DAF Implemented GetEntries, changed to non-dynamic configuration.
|
||
|
; Added code for RBVSE/30's
|
||
|
; 6/28/89 DAF Changed driver name. Added GetEntries. Cleaned up slot interrupt
|
||
|
; allocation stuff. Added 16/25MHz detection and mode checking.
|
||
|
; <1.8> 6/11/89 GGD Get Frame Buffer base from rom tables.
|
||
|
; <1.7> 5/16/89 DAF Fixed GetDefaultMode status call. Updated interrupt level code.
|
||
|
; <1.6> 5/15/89 DAF Many changes. Added fasterAurora fix. Corrected WaitVSync. Added
|
||
|
; SetDefaultMode. Updated setup for new DeclDataRBV
|
||
|
; 5/15/89 DAF Fixed GetDefaultMode. Updated the interrupt level changes to be
|
||
|
; more efficient.
|
||
|
; 5/2/89 DAF More Universal ROM support. Updated interrupt manipulations to
|
||
|
; be more graceful. Reordered private storage. Added Faster Aurora
|
||
|
; time manager hack to overcome RBV interrupt problems.
|
||
|
; <•1.5> 4/15/89 DAF Made a register mistake. Fixed it now..
|
||
|
; <•1.4> 4/15/89 DAF Improved SetGamma, eliminated SetDisable (obsolete). Default
|
||
|
; gamma from gamma directory. Updated hardware accesses for
|
||
|
; universal ROM
|
||
|
; 4/15/89 DAF Updated SetGamma, removed SetDeactive. Tweaked SetGamma to get
|
||
|
; along with Dimmer. Used lo-mems for Universal ROM support.
|
||
|
; <1.3> 3/6/89 GGD Changed RBV register usage now that equates are offsets from
|
||
|
; RBVBase, instead
|
||
|
; <1.2> 2/27/89 DAF Updated scrn resource invalidation in SetDeactive
|
||
|
; <1.1> 11/17/88 DAF Set VDAC pixel read mask in SetEntries control call
|
||
|
; 11/17/88 DAF Set vDAC pixel mask field in SetEntries
|
||
|
; <1.0> 11/11/88 DAF Adding to EASE for the first time.
|
||
|
; 10/26/88 DAF New today
|
||
|
;
|
||
|
|
||
|
STRING C
|
||
|
|
||
|
PRINT OFF
|
||
|
LOAD 'StandardEqu.d'
|
||
|
|
||
|
INCLUDE 'DockingEqu.a'
|
||
|
INCLUDE 'EgretEqu.a'
|
||
|
INCLUDE 'GestaltEqu.a'
|
||
|
INCLUDE 'GestaltPrivateEqu.a'
|
||
|
INCLUDE 'HardwarePrivateEqu.a'
|
||
|
INCLUDE 'IOPrimitiveEqu.a'
|
||
|
INCLUDE 'PowerPrivEqu.a'
|
||
|
INCLUDE 'ROMEqu.a'
|
||
|
INCLUDE 'Video.a'
|
||
|
INCLUDE 'SlotMgrEqu.a'
|
||
|
INCLUDE 'ShutDown.a'
|
||
|
; INCLUDE 'SonicEqu.a'
|
||
|
INCLUDE 'UniversalEqu.a'
|
||
|
|
||
|
INCLUDE 'DepVideoEqu.a'
|
||
|
PRINT ON
|
||
|
|
||
|
SEG '_sRBVDriver'
|
||
|
|
||
|
BLANKS ON
|
||
|
STRING ASIS
|
||
|
MACHINE MC68020
|
||
|
|
||
|
|
||
|
;-------------------------------------------------------------------
|
||
|
; Local Vars, definitions, etc....
|
||
|
;-------------------------------------------------------------------
|
||
|
|
||
|
; This is device storage which is stored in the dCtlStorage field of the DCE.
|
||
|
|
||
|
saveBaseAddr EQU 0 ; the screen base address
|
||
|
saveSQElPtr EQU saveBaseAddr+4 ; the SQ element pointer (for _SIntRemove).
|
||
|
saveGammaPtr EQU saveSQElPtr+4 ; the pointer to the Gamma correction table
|
||
|
saveVDACBase EQU saveGammaPtr+4 ; the base addr of the VDAC
|
||
|
TTask EQU saveVDACBase+4 ; a time manager queue block
|
||
|
GFlags EQU TTask+tmQSize ; flags word
|
||
|
saveMode EQU GFlags+2 ; the current mode setting
|
||
|
saveID EQU saveMode+2 ; monitor type ID
|
||
|
saveGamDispPtr EQU saveID+2 ; pointer to gamma table block
|
||
|
|
||
|
dCtlSize EQU saveGamDispPtr+4 ; size of dCtlStorage
|
||
|
|
||
|
LRBVDriver MAIN EXPORT
|
||
|
|
||
|
;-------------------------------------------------------------------
|
||
|
; Video Driver Header
|
||
|
;-------------------------------------------------------------------
|
||
|
|
||
|
|
||
|
VidDrvr DC.W $4C00 ; ctl,status,needsLock
|
||
|
DC.W 0,0,0 ; not an ornament
|
||
|
|
||
|
; normal entry point offset table for undivided driver, and also the dispatch table
|
||
|
; for the overpatch-resident driver.
|
||
|
|
||
|
DC.W VideoOpen-VidDrvr ; open routine
|
||
|
DC.W VidDrvr-VidDrvr ; no prime in normal video drivers
|
||
|
DC.W VideoCtl-VidDrvr ; control
|
||
|
DC.W VideoStatus-VidDrvr ; status
|
||
|
DC.W VideoClose-VidDrvr ; close
|
||
|
|
||
|
STRING Pascal
|
||
|
VideoTitle DC.B '.Display_Video_Apple_RBV1' ; same name for 25 & 16MHz versions
|
||
|
STRING ASIS
|
||
|
ALIGN 2 ; make sure we're aligned
|
||
|
DC.W 1 ; version = 0
|
||
|
|
||
|
|
||
|
;
|
||
|
; CountTbl is the number of entries to change in each mode, set up to be indexed
|
||
|
; via the modeID.
|
||
|
;
|
||
|
|
||
|
CountTbl DC.B $01,$03,$0F,$FF
|
||
|
|
||
|
;
|
||
|
; The active color table locations in the Cobra system is non-inverted and linearly
|
||
|
; ascending in all screen depths. However, it always places the last active elemnt
|
||
|
; at the end of the CLUT rather than at the beginning (sigh). This table holds
|
||
|
; the offset to the active section of the vDAC for each mode.
|
||
|
;
|
||
|
|
||
|
StartTbl DC.B 254,252,240,0
|
||
|
|
||
|
|
||
|
|
||
|
ALIGN 2 ; correct odd alignment
|
||
|
|
||
|
**********************************************************************
|
||
|
*
|
||
|
* VideoOpen allocates private storage for the device in the DCE and locks
|
||
|
* it down for perpetuity. Also, install the interrupt handler and enable
|
||
|
* the interrupts.
|
||
|
*
|
||
|
* Entry: A0 = param block pointer
|
||
|
* A1 = DCE pointer
|
||
|
*
|
||
|
* Locals: A3 = pointer to private storage
|
||
|
*
|
||
|
**********************************************************************
|
||
|
|
||
|
WITH VDPageInfo,SlotIntQElement
|
||
|
|
||
|
VideoOpen
|
||
|
|
||
|
;
|
||
|
; Allocate private storage (since block is CLEAR, GFlags are zeroed) and get
|
||
|
; a pointer to it in A3
|
||
|
;
|
||
|
|
||
|
MOVEQ #dCtlSize,D0 ; get size of parameters
|
||
|
_ResrvMem ,SYS ; make room as low as possible
|
||
|
MOVEQ #dCtlSize,D0 ; get size of parameters
|
||
|
_NewHandle ,SYS,CLEAR ; get some memory for private storage
|
||
|
BNE OpError1 ; => return an error in open
|
||
|
MOVE.L A0,dCtlStorage(A1) ; save returned handle in DCE
|
||
|
_HLock ; and lock it down forever (this includes a Time Mgr QElem)
|
||
|
|
||
|
MOVE.L (A0),A3 ; get a pointer to it
|
||
|
|
||
|
;
|
||
|
; remember the VDAC base address since it's hard to look up. We don't need to test
|
||
|
; for it since we couldn't get here unless there was an RBV. By the way, we
|
||
|
; don't need to remember the RBV base, since there's a lomem for it.
|
||
|
;
|
||
|
|
||
|
WITH ProductInfo,DecoderInfo
|
||
|
MOVE.L UnivInfoPtr,A0 ; get a pointer to universal data
|
||
|
ADD.L DecoderInfoPtr(A0),A0 ; point to the base address table
|
||
|
MOVE.L VDACAddr(A0),saveVDACBase(A3) ; save pointer
|
||
|
ENDWITH
|
||
|
|
||
|
;
|
||
|
; Initialize and install the time manager task for the RBV interrupt problem. See the
|
||
|
; comment at the end of the driver for more information about the nature of the RBV
|
||
|
; interrupt problem.
|
||
|
;
|
||
|
|
||
|
LEA TimeHandler,A0 ; get a pointer to the task code
|
||
|
MOVE.L A0,tmAddr+TTask(A3) ; put it in the time task
|
||
|
LEA TTask(A3),A0 ; get a pointer to the queue element
|
||
|
_InsTime ; install the task
|
||
|
|
||
|
;
|
||
|
; Get and install the interrupt handler. Call the EnableVGuts utility code to do
|
||
|
; this. This utility also starts the interrupts going. If there is an error
|
||
|
; condition, EnableVGuts returns with Z-bit cleared.
|
||
|
|
||
|
MOVEQ #sqHDSize,D0 ; allocate a slot queue element
|
||
|
_NewPtr ,SYS,CLEAR ; get it from system heap cleared
|
||
|
BNE OpError ; if not allocated, return bad
|
||
|
MOVE.L A0,saveSQElPtr(A3) ; save the SQ element pointer.
|
||
|
|
||
|
BSR EnableVGuts ; do it
|
||
|
BNE OpError ;
|
||
|
|
||
|
;
|
||
|
; read the RBV to find out what kind of monitor we have. If it's a Portrait display (ID=1)
|
||
|
; then set the monochrome only flag. To have gotten here, we MUST have a valid video device.
|
||
|
; We also know that if we read 7 as the monitor type, that we must be in an SE display machine.
|
||
|
; If we weren't, then no display was connected, and this driver would not be open.
|
||
|
;
|
||
|
|
||
|
MOVE.L RBV,A0 ; get the RBV base address
|
||
|
MOVE.B RvMonP(A0),D0 ; get the monitor type
|
||
|
LSR.B #3,D0 ; shift Monitor ID into the low bits
|
||
|
AND.W #7,D0 ; lo 3 bits only
|
||
|
MOVE.W D0,saveID(A3) ; remember it for later
|
||
|
CMP.W #FPIdMono,D0 ; is this the ID for the monochrome portrait display?
|
||
|
BNE.S @Box ; nope, so continue
|
||
|
OR.B #$A0,GFlags(A3) ; yup, so turn on the luminence map and IsMono bits
|
||
|
|
||
|
;
|
||
|
; see if we are on a 16MHz CPU and set the GFlag appropriately. This limits the valid
|
||
|
; screen depths on certain monitors. Since there are no firm plans for SE/30 type machines
|
||
|
; based on this generation, we don't do any special detection here.
|
||
|
;
|
||
|
|
||
|
@Box
|
||
|
CMP.B #BoxAuroraSE16,BoxFlag ; is this a 16MHz RBV machine?
|
||
|
BNE.S @Gamma ; no, so continue
|
||
|
BSET #Is16,GFlags(A3) ; turn on flag bits
|
||
|
|
||
|
;
|
||
|
; load the default gamma table from the slot resource list
|
||
|
;
|
||
|
|
||
|
@Gamma
|
||
|
WITH spBlock
|
||
|
SUBA #spBlockSize,SP ; make a slot parameter block
|
||
|
MOVE.L SP,A0 ; get pointer to block in A0
|
||
|
MOVE.B dCtlSlot(A1),spSlot(A0) ; copy the slot number
|
||
|
MOVE.B dCtlSlotId(A1),spID(A0) ; copy the spID of the video sRsrc <2.0>
|
||
|
CLR.B spExtDev(A0) ; <2.0>
|
||
|
CLR.B spHWDev(A0) ; ????
|
||
|
|
||
|
_sRsrcInfo ; get the spsPointer <2.0>
|
||
|
|
||
|
MOVE.B #sGammaDir,spID(A0) ; look for the gamma directory
|
||
|
_sFindStruct ; get that baby
|
||
|
BNE.S OpError ; if failed, then quit
|
||
|
|
||
|
MOVE.B #$80,spID(A0) ; get the default gamma table, (always 128)
|
||
|
_sGetBlock ; we can use this since we want it on the sys heap
|
||
|
BNE.S OpError ; if failed, then quite
|
||
|
|
||
|
;
|
||
|
; skip over header
|
||
|
;
|
||
|
|
||
|
MOVE.L spResult(A0),A0 ; point to head of the block
|
||
|
MOVE.L A0,saveGamDispPtr(A3) ; remember this block for Close
|
||
|
ADDA #2,A0 ; skip resID
|
||
|
@Name TST.B (A0)+ ; skip over gamma name
|
||
|
BNE.S @Name ;
|
||
|
MOVE.L A0,D0 ; get in d-reg
|
||
|
ADDQ #1,D0 ; word align pointer
|
||
|
BCLR.L #0,D0 ; round it off
|
||
|
|
||
|
MOVE.L D0,saveGammaPtr(A3) ; put it in private storage
|
||
|
ADDA #spBlockSize,SP ; release the parameter block
|
||
|
;
|
||
|
; all done!
|
||
|
;
|
||
|
|
||
|
@AllDone MOVEQ #0,D0 ; no error
|
||
|
EndOpen RTS ; return
|
||
|
|
||
|
OpError
|
||
|
LEA TTask(A3),A0 ; point to the time manager queue element
|
||
|
_RmvTime ; delete it from the queue (no errors)
|
||
|
MOVE.L dCtlStorage(A1),A0 ; get the private storage back
|
||
|
_DisposHandle ; release the driver private storage
|
||
|
OpError1 MOVE.L #OpenErr,D0 ; say can't open driver
|
||
|
ADDA #spBlockSize,SP ; release the spBlock
|
||
|
BRA.S EndOpen
|
||
|
|
||
|
ENDWITH
|
||
|
|
||
|
|
||
|
**********************************************************************
|
||
|
*
|
||
|
* Video Driver Control Call Handler. There are nine calls:
|
||
|
*
|
||
|
* (0) Reset (VAR mode, page: INTEGER; VAR BaseAddr: Ptr);
|
||
|
* (1) KillIO
|
||
|
* (2) SetMode(mode, page: INTEGER; VAR BaseAddr: Ptr);
|
||
|
* (3) SetEntries ( Table: Ptr; Start,Count : integer );
|
||
|
* (4) SetGamma ( Table : Ptr );
|
||
|
* (5) GrayPage (page);
|
||
|
* (6) SetGray (csMode = 0 for color, 1 for gray)
|
||
|
* (7) SetInterrupt ( csMode = 0 for enable, 1 for disable)
|
||
|
* (8) DirectSetEntries (not implemented)
|
||
|
* (9) SetDefaultMode
|
||
|
*
|
||
|
* Entry: A0 = param block pointer
|
||
|
* A1 = DCE pointer
|
||
|
* Uses: A2 = cs parameters (ie. A2 <- csParam(A0)) (must be preserved)
|
||
|
* A3 = scratch (doesn't need to be preserved)
|
||
|
* A4 = scratch (must be preserved)
|
||
|
* D0-D3 = scratch (don't need to be preserved)
|
||
|
*
|
||
|
* Exit: D0 = error code
|
||
|
*
|
||
|
**********************************************************************
|
||
|
|
||
|
;
|
||
|
; Decode the call
|
||
|
;
|
||
|
|
||
|
VideoCtl MOVE.L A0,-(SP) ; save work registers (A0 is saved because it is used by ExitDrvr)
|
||
|
|
||
|
MOVE.W csCode(A0),D0 ; get the opCode
|
||
|
MOVE.L csParam(A0),A2 ; A2 <- Ptr to control parameters
|
||
|
MOVE.L dCtlStorage(A1),A3
|
||
|
MOVE.L (A3),A3 ; get pointer to private storage
|
||
|
|
||
|
CMP.W #9,D0 ; IF csCode NOT IN [0..9] THEN
|
||
|
BHI.S CtlBad ; Error, csCode out of bounds
|
||
|
MOVE.W CtlJumpTbl(PC,D0.W*2),D0 ; Get the relative offset to the routine
|
||
|
JMP CtlJumpTbl(PC,D0.W) ; GOTO the proper routine
|
||
|
|
||
|
CtlJumpTbl DC.W VidReset-CtlJumpTbl ; $00 => VidReset
|
||
|
DC.W CtlGood-CtlJumpTbl ; $01 => CtlGood (no async routines here)
|
||
|
DC.W SetVidMode-CtlJumpTbl ; $02 => SetVidMode
|
||
|
DC.W SetEntries-CtlJumpTbl ; $03 => SetEntries
|
||
|
DC.W SetGamma-CtlJumpTbl ; $04 => SetGamma
|
||
|
DC.W GrayPage-CtlJumpTbl ; $05 => GrayPage
|
||
|
DC.W SetGray-CtlJumpTbl ; $06 => SetGray
|
||
|
DC.W SetInterrupt-CtlJumpTbl ; $07 => SetInterrupt
|
||
|
DC.W CtlBad-CtlJumpTbl ; $08 => DirectSetEntries
|
||
|
DC.W SetDefaultMode-CtlJumpTbl ; $09 => SetDefaultMode
|
||
|
|
||
|
CtlBad MOVEQ #controlErr,D0 ; else say we don't do this one
|
||
|
BRA.S CtlDone ; and return
|
||
|
|
||
|
CtlGood MOVEQ #noErr,D0 ; return no error
|
||
|
|
||
|
CtlDone MOVE.L (SP)+,A0 ; restore registers.
|
||
|
BRA ExitDrvr
|
||
|
|
||
|
|
||
|
|
||
|
VidReset
|
||
|
;---------------------------------------------------------------------
|
||
|
;
|
||
|
; Reset the card to its default
|
||
|
;
|
||
|
;---------------------------------------------------------------------
|
||
|
|
||
|
MOVE #FirstVidMode,csMode(A2) ; return default mode
|
||
|
MOVE #FirstVidMode,saveMode(A3) ; remember FirstVidMode as the requested mode
|
||
|
MOVE #1,D1 ; get default depth in D1
|
||
|
@2 MOVEQ #0,D0 ; get page in D0
|
||
|
MOVE D0,csPage(A2) ; return the page
|
||
|
BSR RBVSetDepth ; set the depth from D1
|
||
|
MOVE.L saveBaseAddr(A3),csBaseAddr(A2) ; return the base address
|
||
|
BSR GrayScreen ; paint the screen gray
|
||
|
BRA.S CtlGood ; => no error
|
||
|
|
||
|
|
||
|
SetVidMode
|
||
|
;---------------------------------------------------------------------
|
||
|
;
|
||
|
; Set the card to the specified mode and page.
|
||
|
; If either is invalid, returns badMode error.
|
||
|
;
|
||
|
; If the card is already set to the specified mode, then do nothing.
|
||
|
;
|
||
|
;---------------------------------------------------------------------
|
||
|
|
||
|
MOVE.W csMode(A2),D1 ; D1 = mode
|
||
|
BSR ChkMode ; check mode
|
||
|
BNE.S CtlBad ; => not a valid mode
|
||
|
|
||
|
CMP.W #0,csPage(A2) ; if not page zero, then return an error
|
||
|
BNE.S CtlBad ; => not a valid page
|
||
|
|
||
|
; Only set the mode if it has changed
|
||
|
; RBVSetDepth updates the saved data in the dCtlStorage
|
||
|
|
||
|
SetEm
|
||
|
MOVE.W csMode(A2),D2 ; get the mode (again)
|
||
|
CMP saveMode(A3),D2 ; has the mode changed?
|
||
|
BEQ.S ModeOK1 ; if not, then we're done
|
||
|
|
||
|
; remember the newly requested mode
|
||
|
|
||
|
MOVE.W D2,saveMode(A3) ; remember requested mode
|
||
|
|
||
|
; set the entire color table to gray before switching to avoid screen anomalies
|
||
|
|
||
|
MOVE.L saveGammaPtr(A3),A0 ; get pointer to gamma data structure
|
||
|
MOVE GFormulaSize(A0),D3 ; get the size of formula data
|
||
|
MOVE.W GDataCnt(A0),D2 ; get number of gamma entries
|
||
|
LSR.W #1,D2 ; divide by two to find midpoint
|
||
|
LEA GFormulaData(A0),A0 ; point to formula data
|
||
|
ADD D3,A0 ; first correction table starts here
|
||
|
MOVE.B (A0,D2),D3 ; get corrected gray from middle of red table
|
||
|
|
||
|
MOVE.W SR,-(SP) ; preserve the status register <2>
|
||
|
MOVEQ #7,D0 ; get mask in D0 <2>
|
||
|
AND.B (SP),D0 ; get the interrupt level <2>
|
||
|
SUBQ.B #2,D0 ; <2>
|
||
|
BGE.S @OK ; if ≥, then don't change <2>
|
||
|
ORI.W #$0200,SR ; raise above level-2 <2>
|
||
|
ANDI.W #$FAFF,SR ; make it level-2 <2>
|
||
|
@OK
|
||
|
|
||
|
BSR WaitVSync ; wait for next blanking period
|
||
|
|
||
|
MOVE.L saveVDACBase(A3),A0 ; get the VDAC base addr
|
||
|
ADDA #vDACwDataReg,A0 ; A0 <- base address of device.
|
||
|
CLR.B vDACwAddReg-vDACwDataReg(A0) ; set the CLUT start address
|
||
|
|
||
|
MOVE #$FF,D2 ; get count
|
||
|
@Repeat MOVE.B D3,(A0) ; put red
|
||
|
MOVE.B D3,(A0) ; put green
|
||
|
MOVE.B D3,(A0) ; put blue
|
||
|
DBRA D2,@Repeat ;
|
||
|
MOVE (SP)+,SR ; restore the status reg
|
||
|
|
||
|
BSR RBVSetDepth ; set the depth, get rowbytes
|
||
|
ModeOK1
|
||
|
|
||
|
NoChange MOVE.L saveBaseAddr(A3),csBaseAddr(A2) ; return the base address
|
||
|
BRA CtlGood ; => return no error
|
||
|
|
||
|
|
||
|
SetEntries
|
||
|
;---------------------------------------------------------------------
|
||
|
;
|
||
|
; Input :
|
||
|
; csParam -> datablock
|
||
|
; datablock = csTable -> table of colorSpecs (not colortable)
|
||
|
; csStart -> where to start setting, or -1
|
||
|
; csCount -> # of entries to change
|
||
|
;
|
||
|
; This call has two modes. In SEQUENCE mode, csCount entries are changed
|
||
|
; in the CLUT, starting at csStart. In INDEX mode, csCount entries are
|
||
|
; installed into the CLUT at the positions specified by their .value fields.
|
||
|
; This mode is selected by passing csStart = -1. In both cases, entries are
|
||
|
; range-checked to the dynamic range of the video mode (bits/pixel).
|
||
|
;
|
||
|
;---------------------------------------------------------------------
|
||
|
;
|
||
|
; Set the CLUT
|
||
|
; A0 = Ptr to the table
|
||
|
; A1 = Ptr to DCE
|
||
|
; A2 = Ptr to cs parameter record
|
||
|
; A3 = Ptr to private data, later to VDAC hardware base
|
||
|
; A4 = Ptr to gamma red table
|
||
|
; A5 = Ptr to gamma green table
|
||
|
; A6 = Ptr to gamma blue table
|
||
|
;
|
||
|
; D0-D3 = Scratch
|
||
|
; D4 = Size of stack color table buffer
|
||
|
; D5 = GFlags word
|
||
|
; D6 = Index range [0..n]
|
||
|
; D7 = gamma channel size in bits
|
||
|
;
|
||
|
;---------------------------------------------------------------------
|
||
|
|
||
|
; Initialize loop.
|
||
|
|
||
|
MOVE.L csTable(A2),D0 ; Check for a nil pointer
|
||
|
BEQ CtlBad
|
||
|
|
||
|
MOVEM.L A1/A4-A6/D4-D7,-(SP) ; save registers for gamma
|
||
|
|
||
|
MOVE.W GFlags(A3),D5 ; get GFlags word in D5
|
||
|
|
||
|
CMP.W #-1,csStart(A2) ; is it sequence mode?
|
||
|
BEQ.S @5 ; nope, it's index
|
||
|
BSET #UseSeq,D5 ; if sequence then set bit (it's always clear in GFlags)
|
||
|
@5
|
||
|
MOVE.L saveGammaPtr(A3),A0 ; get pointer to gamma data structure
|
||
|
MOVE.W GFormulaSize(A0),D0 ; get the size of formula data
|
||
|
LEA GFormulaData(A0),A4 ; point to formula data
|
||
|
ADD D0,A4 ; red correction table starts here
|
||
|
MOVE.L A4,A5 ; get default pointer to green data
|
||
|
MOVE.L A4,A6 ; get default pointer to blue data
|
||
|
MOVE GDataWidth(A0),D7 ; get width of each entry in bits
|
||
|
CMP #1,GChanCnt(A0) ; if only only one table, we're set
|
||
|
BEQ.S OneTbl ; => just one table
|
||
|
|
||
|
MOVE GDataCnt(A0),D0 ; get # entries in table
|
||
|
MOVE D7,D1 ; copy it to goof around
|
||
|
ADD #7,D1 ; round to nearest byte
|
||
|
LSR #3,D1 ; get bytes per entry
|
||
|
MULU D1,D0 ; get size of table in bytes
|
||
|
|
||
|
ADDA D0,A5 ; calc base of green
|
||
|
ADDA D0,A6 ; calc base of blue
|
||
|
ADDA D0,A6 ; calc base of blue
|
||
|
|
||
|
OneTbl
|
||
|
|
||
|
; get the maximum number of entries, zero based from a convenient table
|
||
|
|
||
|
MOVE.W saveMode(A3),D1 ; get the current video mode
|
||
|
SUB.W #FirstVidMode,D1 ; convert to index
|
||
|
|
||
|
LEA CountTbl,A1 ; point to little table of counts
|
||
|
MOVE.B (A1,D1),D6 ; pick the zero-based byte
|
||
|
LEA StartTbl,A1 ; point to table of vDAC start positions for each mode
|
||
|
MOVE.B (A1,D1),D5 ; hide this byte in lo-half of D5
|
||
|
|
||
|
;
|
||
|
; allocate a temporary color table on the stack. We'll pre-process all the entries that will
|
||
|
; change here so we can hit the hardware as quickly as possible.
|
||
|
;
|
||
|
|
||
|
MOVE.W csCount(A2),D3 ; get the number of entries to change
|
||
|
CMP.B D6,D3 ; is it in the allowable range?
|
||
|
BHI BadExit ; if outside, then exit w/bad result
|
||
|
|
||
|
MOVE.L D3,D4 ; make a copy of the table size (zero-based!)
|
||
|
ADDQ #1,D4 ; make it a counting number
|
||
|
BTST #UseSeq,D5 ; are we in index or sequential mode?
|
||
|
BEQ.S @isIndex ; if equal, we're indexed
|
||
|
@isSeq MULU #3,D4 ; multiply times 3 for sequential mode
|
||
|
BRA.S @allocIt ; and continue
|
||
|
@isIndex ASL #2,D4 ; multiply times 4 (always less than 1024)
|
||
|
@allocIt SUB.W D4,SP ; allocate the buffer
|
||
|
|
||
|
;
|
||
|
; construct the stack version of the color table. It looks like a color table, but each of the
|
||
|
; four components is only eight bits (rather than 16).
|
||
|
;
|
||
|
|
||
|
MOVE.L SP,A0 ; copy the stack buffer pointer
|
||
|
MOVE.L csTable(A2),A1 ; get colorSpec pointer in A1
|
||
|
|
||
|
; write the index if in indexed mode. If in sequential eight mode, blow it off
|
||
|
; completely, since it won't be needed.
|
||
|
|
||
|
SetupLoop
|
||
|
MOVE.W (A1)+,D0 ; get index
|
||
|
|
||
|
BTST #UseSeq,D5 ; is it sequence mode?
|
||
|
BNE.S @SLSeq ; yup, so go there
|
||
|
|
||
|
ADD.B D5,D0 ; add the screen depth clut offset
|
||
|
|
||
|
MOVE.B D0,(A0)+ ; put in stack table
|
||
|
|
||
|
@SLSeq
|
||
|
MOVE.W (A1)+,D0 ; get red
|
||
|
MOVE.W (A1)+,D1 ; get green
|
||
|
MOVE.W (A1)+,D2 ; get blue
|
||
|
|
||
|
TST D5 ; test hi bit of the flags
|
||
|
BPL.S NoGray ; if not set, don't luminence map
|
||
|
|
||
|
; we're luminence mapping here
|
||
|
|
||
|
MULU #$4CCC,D0 ; multiply by red weight (0.30)
|
||
|
MULU #$970A,D1 ; multiply by green weight (0.59)
|
||
|
MULU #$1C29,D2 ; multiply by blue weight (0.11)
|
||
|
ADD.L D1,D0 ; sum red and green
|
||
|
ADD.L D2,D0 ; blue also
|
||
|
BFEXTU D0{0:D7},D1 ; get gChanWidth bits for gamma table lookup
|
||
|
MOVE.W D1,D0 ; copy into red register
|
||
|
MOVE.W D1,D2 ; copy into blue register
|
||
|
|
||
|
BRA.S WriteSP ; go on and write it in the stack buffer
|
||
|
|
||
|
NoGray
|
||
|
BFEXTU D0{16:D7},D0 ; get gChanWidth bits of red
|
||
|
BFEXTU D1{16:D7},D1 ; get gChanWidth bits of green
|
||
|
BFEXTU D2{16:D7},D2 ; get gChanWidth bits of blue
|
||
|
|
||
|
WriteSP
|
||
|
BTST #IsMono,D5 ; if monochrome display, write black to red & green
|
||
|
BEQ.S Brighter ; if not, then set all three channels
|
||
|
CLR.W (A0)+ ; write black for green and blue
|
||
|
BRA.S Looper ; write out normal blue
|
||
|
Brighter
|
||
|
MOVE.B (A4,D0),(A0)+ ; write gamma corrected red
|
||
|
MOVE.B (A5,D1),(A0)+ ; write gamma corrected green
|
||
|
Looper
|
||
|
MOVE.B (A6,D2),(A0)+ ; write gamma corrected blue
|
||
|
DBRA D3,SetupLoop ; and loop for each entry
|
||
|
|
||
|
;
|
||
|
; OK, the stack table is set up. Now let's load the hardware.
|
||
|
;
|
||
|
|
||
|
MOVE.W csCount(A2),D3 ; get the count again
|
||
|
|
||
|
MOVE.L saveVDACBase(A3),A3 ; get VDAC base from driver privates
|
||
|
MOVE.B #$FF,vDACPixRdMask(A3) ; enable all bits in the pixel mask
|
||
|
|
||
|
LEA vDACwDataReg(A3),A3 ; point to vDAC data write register
|
||
|
|
||
|
MOVE.W SR,-(SP) ; preserve the status register <2>
|
||
|
MOVEQ #7,D0 ; get mask in D0 <2>
|
||
|
AND.B (SP),D0 ; get the interrupt level <2>
|
||
|
SUBQ.B #2,D0 ; <2>
|
||
|
BGE.S @OK ; if ≥, then don't change <2>
|
||
|
ORI.W #$0200,SR ; raise above level-2 <2>
|
||
|
ANDI.W #$FAFF,SR ; make it level-2 <2>
|
||
|
@OK
|
||
|
|
||
|
BSR WaitVSync ; wait for next blanking period (preserves A0)
|
||
|
|
||
|
LEA 2(SP),A0 ; point to the stack buffer again
|
||
|
|
||
|
BTST #UseSeq,D5 ; is it sequence mode?
|
||
|
BNE.S SeqWrite ; yup, sequence mode, so go
|
||
|
|
||
|
;
|
||
|
; here's a loop that actually writes to the hardware when in indexed mode
|
||
|
;
|
||
|
|
||
|
IndexWrite
|
||
|
MOVE.B (A0)+,vDACwAddReg-vDACwDataReg(A3) ; write the index value to the CLUT address r
|
||
|
MOVE.B (A0)+,(A3) ; write red
|
||
|
MOVE.B (A0)+,(A3) ; write green
|
||
|
MOVE.B (A0)+,(A3) ; write blue
|
||
|
DBRA D3,IndexWrite ; and loop
|
||
|
BRA.S SEDone ;
|
||
|
|
||
|
; write the translated starting position for sequence mode
|
||
|
|
||
|
SeqWrite
|
||
|
|
||
|
MOVE.W csStart(A2),D0 ; get sequence start address
|
||
|
ADD.B D5,D0 ; offset for this mode (never greater then 255!)
|
||
|
MOVE.B D0,vDACwAddReg-vDACwDataReg(A3) ; write the sequence start position
|
||
|
|
||
|
;
|
||
|
; here's the loop that actually writes to the hardware when in sequence mode
|
||
|
;
|
||
|
|
||
|
SeqLoop
|
||
|
MOVE.B (A0)+,(A3) ; get red
|
||
|
MOVE.B (A0)+,(A3) ; get green
|
||
|
MOVE.B (A0)+,(A3) ; write blue
|
||
|
DBRA D3,SeqLoop ; and loop
|
||
|
|
||
|
;
|
||
|
; clean up and go home
|
||
|
;
|
||
|
|
||
|
SEDone
|
||
|
MOVE (SP)+,SR ; restore status register
|
||
|
ADD D4,SP ; release stack buffer
|
||
|
MOVEM.L (SP)+,A1/A4-A6/D4-D7 ; restore registers
|
||
|
BRA CtlGood ; return O-Tay!
|
||
|
|
||
|
BadExit MOVEM.L (SP)+,A1/A4-A6/D4-D7 ; restore registers
|
||
|
BRA CtlBad ; return an error code
|
||
|
|
||
|
|
||
|
SetGamma
|
||
|
;---------------------------------------------------------------------
|
||
|
;
|
||
|
; Set the gamma table. This call copies the supplied gTable so the
|
||
|
; caller does not have to put the source on the system heap. It
|
||
|
; tests if the gamma table is exactly a match to the currently
|
||
|
; connected monitor, or always allows it if the monitor number in
|
||
|
; the FormulaData is -1. If supplied gamma table ptr is NIL, then
|
||
|
; it loads a linear gamma table into the private table
|
||
|
;
|
||
|
; A0 = Ptr to private storage
|
||
|
; A1 = Ptr to DCE
|
||
|
; A2 = Ptr to cs parameter record
|
||
|
;
|
||
|
;---------------------------------------------------------------------
|
||
|
|
||
|
; get new gamma table and check that we know how to handle it
|
||
|
|
||
|
MOVE.L csGTable(A2),D0 ; test for a NIL pointer
|
||
|
BEQ LinearTab ; if so, then set up a linear gamma table
|
||
|
MOVE.L D0,A2 ; get pointer to new gamma table
|
||
|
|
||
|
TST.W GVersion(A2) ; version = 0?
|
||
|
BNE CtlBad ; => no, return error
|
||
|
TST.W GType(A2) ; test the hardware ID
|
||
|
BEQ.S ChangeTable ; if 0, then accept a TFB gamma table
|
||
|
CMP.W #drHwRBV,GType(A2) ; type = Aurora?
|
||
|
BNE CtlBad ; => no, return error
|
||
|
TST.W gFormulaSize(A2) ; if gType=Aurora, then check for monID in gFormulaData
|
||
|
BEQ.S ChangeTable ; if zero, then generic, so continue
|
||
|
|
||
|
MOVE.W gFormulaData(A2),D0 ; get the monitor ID this table was intended for
|
||
|
CMP.W saveID(A3),D0 ; is this the monitor?
|
||
|
BEQ.S ChangeTable ; yes, so do it
|
||
|
ADDQ #1,D0 ; was it -1?
|
||
|
BNE CtlBad ; nope, so must be wrong monitor
|
||
|
|
||
|
; if new table is different size, reallocate memory
|
||
|
|
||
|
ChangeTable
|
||
|
MOVE.L saveGammaPtr(A3),A0 ; get current gamma in A0
|
||
|
MOVE GFormulaSize(A2),D0 ; get size of formula in new
|
||
|
CMP GFormulaSize(A0),D0 ; same as current gamma table
|
||
|
BNE.S @GetNew ; =>no, resize pointer
|
||
|
MOVE GChanCnt(A2),D0 ; get number of tables in new
|
||
|
CMP GChanCnt(A0),D0 ; same as current gamma table?
|
||
|
BEQ.S @SizeOK ; => yes, data size ok
|
||
|
BGT.S @GetNew ; => new one is bigger, save old one
|
||
|
@NewSize _DisposPtr ; if new one smaller, dispose old one
|
||
|
CLR.L saveGammaPtr(A3) ; flag it's been disposed
|
||
|
|
||
|
@GetNew MOVE GDataCnt(A2),D0 ; get number of entries
|
||
|
MULU GChanCnt(A2),D0 ; multiply by number of tables
|
||
|
ADD GFormulaSize(A2),D0 ; add size of formula data
|
||
|
ADD #GFormulaData,D0 ; add gamma table header size
|
||
|
_NewPtr ,Sys ; and allocate a new pointer
|
||
|
BNE CtlBad ; => unable to allocate storage
|
||
|
|
||
|
MOVE.L saveGammaPtr(A3),D0 ; get old gamma table
|
||
|
MOVE.L A0,saveGammaPtr(A3) ; save new gamma table
|
||
|
TST.L D0 ; was there an old one?
|
||
|
BEQ.S @SizeOK ; => no, already disposed
|
||
|
MOVE.L D0,A0 ; else get old table
|
||
|
_DisposPtr ; and dispose of old gamma table
|
||
|
|
||
|
MOVE.L saveGammaPtr(A3),A0 ; get new gamma table back
|
||
|
|
||
|
; copy the gamma table header
|
||
|
|
||
|
@SizeOK MOVE GChanCnt(A2),D0 ; get number of tables
|
||
|
MOVE GFormulaSize(A2),D1 ; get size of formula data
|
||
|
MOVE gDataCnt(A2),D2 ; get number of entries
|
||
|
MOVE.L (A2)+,(A0)+ ; copy gamma header
|
||
|
MOVE.L (A2)+,(A0)+ ; which is
|
||
|
MOVE.L (A2)+,(A0)+ ; 12 bytes long
|
||
|
|
||
|
; copy the data
|
||
|
|
||
|
MULU D0,D2 ; multiply by number of tables
|
||
|
ADD D1,D2 ; add in size of formula data
|
||
|
SUBQ #1,D2 ; get count - 1
|
||
|
@NxtByte MOVE.B (A2)+,D0 ; get a byte
|
||
|
MOVE.B D0,(A0)+ ; move a byte
|
||
|
DBRA D2,@NxtByte ; => repeat for all bytes
|
||
|
|
||
|
BRA CtlGood ; => return no error
|
||
|
|
||
|
;
|
||
|
; set up a linear gamma table. To prevent memory thrash, build this new one
|
||
|
; the same size as the existing one (one or three channel)
|
||
|
;
|
||
|
|
||
|
LinearTab
|
||
|
MOVE.L saveGammaPtr(A3),A0 ; get current gamma in A2
|
||
|
MOVE.W GFormulaSize(A0),D0 ; get size of formula in new
|
||
|
MOVE.W GChanCnt(A0),D2 ; get the number of tables
|
||
|
SUBQ #1,D2 ; zero based, of course
|
||
|
ADDA #GFormulaData,A0 ; point to tables
|
||
|
ADDA D0,A0 ; point past monID, if present
|
||
|
@ChanLoop MOVE.W #255,D0 ; loop count within each channel
|
||
|
@entryLoop MOVE.B D0,(A0) ; write value
|
||
|
NOT.B (A0)+ ; invert it to make table ramp properly
|
||
|
DBRA D0,@entryLoop ; for each entry in channel
|
||
|
DBRA D2,@ChanLoop ; and each channel
|
||
|
BRA CtlGood ; all done
|
||
|
|
||
|
|
||
|
GrayPage
|
||
|
;---------------------------------------------------------------------
|
||
|
;
|
||
|
; Clear the specified page in the current mode to gray
|
||
|
;
|
||
|
; A0 = Ptr to private storage
|
||
|
; A1 = Ptr to DCE
|
||
|
; A2 = Ptr to cs parameter record
|
||
|
;
|
||
|
;---------------------------------------------------------------------
|
||
|
|
||
|
MOVE saveMode(A3),D1 ; D1 = mode
|
||
|
MOVE D1,csMode(A2) ; force current mode, just in case for ChkPage
|
||
|
BSR ChkMode ; convert mode to depth in D1
|
||
|
BNE CtlBad ; => not a valid depth
|
||
|
|
||
|
MOVE csPage(A2),D0 ; D0 = page
|
||
|
BNE CtlBad ; => not a valid page
|
||
|
|
||
|
BSR GrayScreen ; paint the screen gray
|
||
|
|
||
|
BRA CtlGood ; => return no error
|
||
|
|
||
|
|
||
|
SetGray
|
||
|
;---------------------------------------------------------------------
|
||
|
;
|
||
|
; Set luminance mapping on (csMode = 1) or off (csMode = 0)
|
||
|
;
|
||
|
; When luminance mapping is on, RGB values passed to setEntries are mapped
|
||
|
; to grayscale equivalents before they are written to the CLUT.
|
||
|
;
|
||
|
; A1 = Ptr to DCE
|
||
|
; A2 = Ptr to cs parameter record
|
||
|
;
|
||
|
;---------------------------------------------------------------------
|
||
|
|
||
|
BTST #IsMono,GFlags(A3) ; is this a mono-only monitor?
|
||
|
BEQ.S @1 ; if not, then go ahead
|
||
|
MOVE.B #1,csMode(A2) ; always turn on for mono devices
|
||
|
@1 MOVEQ #0,D1 ; set up for BFEXTU to point to GrayFlag
|
||
|
BSR.S SetIntCom ; call common code
|
||
|
BRA CtlGood ; all done
|
||
|
|
||
|
;
|
||
|
; this shared routine setup up a flag in GFlags. It takes a pointer to
|
||
|
; private storage in A3, and the bit field start location in D1
|
||
|
;
|
||
|
|
||
|
SetIntCom
|
||
|
MOVE.B csMode(A2),D0 ; get boolean
|
||
|
BFINS D0,GFlags(A3){D1:1} ; set flag bit
|
||
|
RTS ; and return
|
||
|
|
||
|
|
||
|
SetInterrupt
|
||
|
;---------------------------------------------------------------------
|
||
|
;
|
||
|
; Enable (csMode = 0) or disable (csMode = 1) VBL interrupts
|
||
|
;
|
||
|
; As a future performance enhancement, interrupts on the card can be
|
||
|
; disabled or enabled from software. For instance, if the cursor is
|
||
|
; not on a screen, and there is nothing in the Slot Interrupt Queue
|
||
|
; for that device, interrupts may be disabled reducing interrupt
|
||
|
; overhead for the system.
|
||
|
;
|
||
|
; The slot interrupt queue element is always allocated by the Open call.
|
||
|
; This routine just inserts and removes it from the slot interrupt task queue.
|
||
|
;
|
||
|
; A1 = Ptr to DCE
|
||
|
; A2 = Ptr to cs parameter record
|
||
|
; A3 = Ptr to private storage
|
||
|
;
|
||
|
;---------------------------------------------------------------------
|
||
|
|
||
|
WITH VDPageInfo,SlotIntQElement
|
||
|
|
||
|
MOVEQ #1,D1 ; set up for BFEXTU to point to IntDisFlag
|
||
|
BSR.S SetIntCom ; call common code
|
||
|
BNE.S DisableThem ; if zero, then enable
|
||
|
|
||
|
;
|
||
|
; this code enables interrupts and installs the interrupt handler
|
||
|
;
|
||
|
|
||
|
BSR.S EnableVGuts ; call common code
|
||
|
BNE CtlBad ; error, flag problem
|
||
|
BRA CtlGood ; and go home
|
||
|
|
||
|
;
|
||
|
; this code disables VBL interrupts, then removes the interrupt handler
|
||
|
;
|
||
|
|
||
|
DisableThem
|
||
|
BSR.S DisableVGuts ; jump to the disabling utility
|
||
|
BRA CtlGood ; all done
|
||
|
|
||
|
;
|
||
|
; the following two routines are common code shared between the Open/Close calls
|
||
|
; and the SetInterrupt control call
|
||
|
;
|
||
|
|
||
|
DisableVGuts
|
||
|
BSR WaitVSync ; to be safe, wait for the next VBL
|
||
|
MOVE.L RBV,A0 ; point to the RBV base
|
||
|
MOVE.B #$40,RvSEnb(A0) ; set slot 0 interrupt disabled (slot 0 bit+set/clear to 0) <1.3>
|
||
|
|
||
|
CLR D0 ; setup slot # for _SIntRemove (slot zero!)
|
||
|
MOVE.L saveSQElPtr(A3),A0 ; get the SQ element pointer
|
||
|
_SIntRemove ; remove the interrupt handler
|
||
|
RTS
|
||
|
|
||
|
EnableVGuts ;
|
||
|
MOVE.L saveSQElPtr(A3),A0 ; get the queue element
|
||
|
LEA BeginIH,A2 ; save Pointer to interrupt handler
|
||
|
MOVE.W #SIQType,SQType(A0) ; setup queue ID
|
||
|
MOVE.L A2,SQAddr(A0) ; setup int routine address
|
||
|
MOVE.L dCtlStorage(A1),A2 ; base handle to privates
|
||
|
MOVE.L (A2),A2 ; pointer to privates (this must stay locked!!)
|
||
|
MOVE.L A2,SQParm(A0) ; pass this as the parameter
|
||
|
CLR.W D0 ; setup slot zero
|
||
|
_SIntInstall ; and do install
|
||
|
BNE.S IntBad
|
||
|
|
||
|
MOVE.L A0,-(SP) ; save this for a second
|
||
|
MOVE.L RBV,A0 ; point to the RBV base
|
||
|
MOVE.B #$C0,RvSEnb(A0) ; set slot 0 interrupt enabled (slot 0 bit+set/clear to 1) <1.3>
|
||
|
MOVE.L (SP)+,A0
|
||
|
|
||
|
MOVE D0,D0 ; clear z-bit for good result
|
||
|
RTS ; return home
|
||
|
|
||
|
;
|
||
|
; in the event there is a problem, return Z-flag off
|
||
|
;
|
||
|
|
||
|
IntBad
|
||
|
MOVEQ #1,D0 ; clear Z bit
|
||
|
RTS
|
||
|
|
||
|
ENDWITH
|
||
|
|
||
|
|
||
|
SetDefaultMode
|
||
|
;---------------------------------------------------------------------
|
||
|
;
|
||
|
; Write the card default mode into slot pRAM.
|
||
|
;
|
||
|
; A1 = Ptr to DCE
|
||
|
; A2 = Ptr to cs parameter record
|
||
|
; A3 = Ptr to private storage
|
||
|
;
|
||
|
; This routine is called by Monitors when somebody selects an alternate
|
||
|
; video mode family in the Options dialog.
|
||
|
;
|
||
|
;---------------------------------------------------------------------
|
||
|
|
||
|
WITH spBlock
|
||
|
|
||
|
;
|
||
|
; set up a slot parameter block on the stack
|
||
|
;
|
||
|
|
||
|
|
||
|
SUBA #spBlockSize,SP ; make an slot parameter block on stack
|
||
|
MOVE.L SP,A0 ; get pointer to parm block now
|
||
|
MOVE.B dCtlSlot(A1),spSlot(A0) ; put slot in pBlock
|
||
|
CLR.B spExtDev(A0) ; external device = 0
|
||
|
|
||
|
|
||
|
;
|
||
|
; read the slot pRAM to determine what the currently saved mode is. The first
|
||
|
; word is the board ID, followed by the default screen depth. Aurora keeps the video sRsrc
|
||
|
; spID in VendorUse2. This guy DOESN'T check to make sure that the mode being set if
|
||
|
; valid for the display, but that's OK since Monitors can't see the other modes anyway
|
||
|
;
|
||
|
|
||
|
SUBA #SizesPRAMRec,SP ; allocate block for pRAM record
|
||
|
MOVE.L SP,spResult(A0) ; point to it
|
||
|
_sReadPRAMRec ; read it
|
||
|
|
||
|
;
|
||
|
; The parameter list id (identifying the screen depth) in 2(SP) will still be valid.
|
||
|
;
|
||
|
; It is very important that Monitors (or someone) invalidate and setup the screen resource
|
||
|
; if this call is exercised. Monitors needs to verify (and potentially re-write to pRAM)
|
||
|
; the proper screen depth in the new world.
|
||
|
;
|
||
|
|
||
|
MOVE.B csMode(A2),3(SP) ; write the mode into pRAM buffer
|
||
|
|
||
|
MOVE.L SP,spsPointer(A0) ; set up parameter block
|
||
|
_SPutPRAMRec ; write the new record out
|
||
|
ADDA #SizesPRAMRec+spBlockSize,SP ; deallocate buffer
|
||
|
BRA CtlGood
|
||
|
|
||
|
|
||
|
|
||
|
**********************************************************************
|
||
|
*
|
||
|
* VideoClose releases the device's private storage and removes the
|
||
|
* interrupt handler.
|
||
|
*
|
||
|
*
|
||
|
* Entry: A0 = param block pointer
|
||
|
* A1 = DCE pointer
|
||
|
*
|
||
|
* Other: A2 = temporary DCE pointer copy
|
||
|
*
|
||
|
**********************************************************************
|
||
|
|
||
|
VideoClose
|
||
|
|
||
|
MOVE.L dCtlStorage(A1),A3
|
||
|
MOVE.L (A3),A3 ; get pointer to private storage
|
||
|
|
||
|
BSR DisableVGuts ; call utility to deactivate interrupts
|
||
|
|
||
|
LEA TTask(A3),A0 ; get the time manager task block
|
||
|
_RmvTime ; remove this element from the queue
|
||
|
|
||
|
|
||
|
MOVE.L saveSQElPtr(A3),A0 ; get the slot interrupt queue element ptr
|
||
|
_DisposPtr
|
||
|
|
||
|
MOVE.L saveGamDispPtr(A3),A0 ; get pointer to gamma table
|
||
|
_DisposPtr ; and dispose it
|
||
|
|
||
|
MOVE.L dCtlStorage(A1),A0 ; Dispose of the private storage
|
||
|
_DisposHandle ;
|
||
|
|
||
|
MOVEQ #0,D0 ; no error
|
||
|
RTS ; and return
|
||
|
|
||
|
|
||
|
**********************************************************************
|
||
|
*
|
||
|
* Video Driver Status Call Handler. Right now there are nine calls:
|
||
|
*
|
||
|
* (0) Error
|
||
|
* (1) Error
|
||
|
* (2) GetMode
|
||
|
* (3) GetEntries
|
||
|
* (4) GetPage
|
||
|
* (5) GetPageBase
|
||
|
* (6) GetGray
|
||
|
* (7) GetInterrupt
|
||
|
* (8) GetGamma
|
||
|
* (9) GetDefaultMode
|
||
|
*
|
||
|
* Entry: A0 = param block
|
||
|
* A1 = DCE pointer
|
||
|
* Uses: A2 = cs parameters
|
||
|
* A3 = pointer to private storage
|
||
|
* D0-D3 = scratch (don't need to be preserved)
|
||
|
*
|
||
|
* Exit: D0 = error code
|
||
|
*
|
||
|
**********************************************************************
|
||
|
|
||
|
VideoStatus
|
||
|
|
||
|
MOVE.L A0,-(SP) ; save a register
|
||
|
MOVE.W csCode(A0),D0 ; get the opCode
|
||
|
MOVE.L csParam(A0),A2 ; A2 <- Ptr to control parameters
|
||
|
MOVE.L dCtlStorage(A1),A3
|
||
|
MOVE.L (A3),A3 ; get pointer to private storage
|
||
|
|
||
|
|
||
|
CMP.W #9,D0 ;IF csCode NOT IN [0..9] THEN
|
||
|
BHI.S StatBad ; Error, csCode out of bounds.
|
||
|
LSL.W #1,D0 ;Adjust csCode to be an index into the table.
|
||
|
MOVE.W StatJumpTbl(PC,D0.W),D0 ;Get the relative offset to the routine.
|
||
|
JMP StatJumpTbl(PC,D0.W) ;GOTO the proper routine.
|
||
|
|
||
|
StatJumpTbl DC.W StatBad-StatJumpTbl ;$00 => Error
|
||
|
DC.W StatBad-StatJumpTbl ;$01 => Error
|
||
|
DC.W GetMode-StatJumpTbl ;$02 => GetMode
|
||
|
DC.W GetEntries-StatJumpTbl ;$03 => GetEntries
|
||
|
DC.W GetPage-StatJumpTbl ;$04 => GetPage
|
||
|
DC.W GetPageBase-StatJumpTbl ;$05 => GetPageBase
|
||
|
DC.W GetGray-StatJumpTbl ;$06 => GetGray
|
||
|
DC.W GetInterrupt-StatJumpTbl ;$07 => GetInterrupt
|
||
|
DC.W GetGamma-StatJumpTbl ;$08 => GetGamma
|
||
|
DC.W GetDefaultMode-StatJumpTbl ;$09 => GetDefaultMode
|
||
|
|
||
|
|
||
|
StatBad MOVEQ #statusErr,D0 ; else say we don't do this one
|
||
|
BRA.S StatDone ; and return
|
||
|
|
||
|
StatGood MOVEQ #noErr,D0 ; return no error
|
||
|
|
||
|
StatDone MOVE.L (SP)+,A0 ; restore registers.
|
||
|
BRA ExitDrvr
|
||
|
|
||
|
|
||
|
GetMode
|
||
|
;---------------------------------------------------------------------
|
||
|
;
|
||
|
; Return the current mode
|
||
|
;
|
||
|
; Inputs : A2 = pointer to csParams
|
||
|
; A3 = pointer to private storage
|
||
|
;
|
||
|
;---------------------------------------------------------------------
|
||
|
|
||
|
MOVE.W saveMode(A3),csMode(A2) ; return the mode
|
||
|
CLR.W csPage(A2) ; return the page number
|
||
|
MOVE.L saveBaseAddr(A3),csBaseAddr(A2) ; and the base address
|
||
|
|
||
|
BRA.S StatGood ; => return no error
|
||
|
|
||
|
|
||
|
GetEntries
|
||
|
;---------------------------------------------------------------------
|
||
|
;
|
||
|
; Read the current contents of the CLUT. These values were gamma corrected
|
||
|
; when they were set (by SetEntries), so they may not match the source
|
||
|
; cSpec array.
|
||
|
;
|
||
|
; Inputs : A2 = pointer to csParams
|
||
|
;
|
||
|
;---------------------------------------------------------------------
|
||
|
|
||
|
MOVE.L csTable(A2),D0 ; Check for a nil pointer
|
||
|
BEQ.S StatBad
|
||
|
|
||
|
MOVEM.L A1/A3/A4/D4/D1,-(SP) ; save work registers
|
||
|
MOVE.L D0,A4 ; A4 <- pointer to table
|
||
|
|
||
|
; calculate the index range in D3
|
||
|
|
||
|
MOVE.W saveMode(A3),D1 ; get the current video mode
|
||
|
SUB.W #FirstVidMode,D1 ; convert to index
|
||
|
LEA CountTbl,A0 ; point to little table of counts
|
||
|
MOVE.B (A0,D1),D3 ; pick the zero-based byte
|
||
|
LEA StartTbl,A0 ; point to table of starting positions
|
||
|
MOVE.B (A0,D1),D4 ; pick up start offset position
|
||
|
|
||
|
MOVE.W csCount(A2),D0 ; get the count
|
||
|
MOVE.W D0,D2 ; make a copy of the count
|
||
|
|
||
|
CMP.W #-1,csStart(A2) ; is it index or sequence mode?
|
||
|
BEQ.S GECom ; if index, then continue
|
||
|
|
||
|
MOVE.W D0,D1 ; copy count into another loop counter
|
||
|
ADD.W csStart(A2),D2 ; get last index
|
||
|
@1
|
||
|
MOVE.W D2,value(A4,D1*8) ; write the index into the table
|
||
|
SUBQ #1,D2 ; decrease index
|
||
|
DBRA D1,@1 ; for all indices
|
||
|
|
||
|
GECom
|
||
|
|
||
|
MOVE.L saveVDACBase(A3),A1 ; get base address of CLUT
|
||
|
ADDQ #vDACwDataReg,A1 ; read and write data are the same register
|
||
|
|
||
|
MOVE.W SR,-(SP) ; preserve the status register
|
||
|
MOVEQ #7,D1 ; get mask in D0
|
||
|
AND.B (SP),D1 ; get the interrupt level
|
||
|
SUBQ.B #2,D1 ;
|
||
|
BGE.S @OK ; if ≥, then don't change
|
||
|
ORI.W #$0200,SR ; raise above level-2
|
||
|
ANDI.W #$FAFF,SR ; make it level-2
|
||
|
@OK
|
||
|
@Repeat
|
||
|
MOVE.W value(A4),D1 ; get the next position in D1
|
||
|
CMP.B D3,D1 ; Is this request in range?
|
||
|
BHI.S @Until ; if hi, then no, the request is invalid
|
||
|
|
||
|
ADD.B D4,D1 ; offset it's position for pixel depth
|
||
|
MOVE.B D1,vDACrAddReg-vDACwDataReg(A1) ; set the CLUT to read from this addr
|
||
|
|
||
|
MOVE.B (A1),D1 ; get red
|
||
|
MOVE.B D1,rgb+red(A4) ; byte->word in the dest cSpecArray
|
||
|
MOVE.B D1,rgb+red+1(A4) ;
|
||
|
|
||
|
MOVE.B (A1),D1 ; get green
|
||
|
MOVE.B D1,rgb+green(A4) ;
|
||
|
MOVE.B D1,rgb+green+1(A4) ;
|
||
|
|
||
|
MOVE.B (A1),D1 ; get blue
|
||
|
MOVE.B D1,rgb+blue(A4) ;
|
||
|
MOVE.B D1,rgb+blue+1(A4) ;
|
||
|
|
||
|
@Until ADDQ.L #colorSpecSize,A4 ; advance A4 to the next color table element
|
||
|
DBRA D0,@Repeat ; and loop until done
|
||
|
|
||
|
MOVE (SP)+,SR ; restore the status register
|
||
|
|
||
|
MOVEM.L (SP)+,A1/A3/A4/D4/D1 ; restore work register
|
||
|
BRA StatGood ; => return no error
|
||
|
|
||
|
|
||
|
GetPage
|
||
|
;---------------------------------------------------------------------
|
||
|
;
|
||
|
; Return the number of pages in the specified mode. Cobra always has
|
||
|
; one video page, so this is pretty simple.
|
||
|
;
|
||
|
;---------------------------------------------------------------------
|
||
|
|
||
|
MOVE csMode(A2),D1 ; get the mode
|
||
|
MOVE D1,D2 ; keep a copy
|
||
|
BSR.S ChkMode ; is this mode OK?
|
||
|
BGT StatBad ; => not a valid mode
|
||
|
|
||
|
MOVE.W #1,csPage(A2) ; return page count
|
||
|
BRA StatGood ; => return no error
|
||
|
|
||
|
|
||
|
GetPageBase
|
||
|
;---------------------------------------------------------------------
|
||
|
;
|
||
|
; Return the base address for the specified page in the current mode
|
||
|
;
|
||
|
;---------------------------------------------------------------------
|
||
|
|
||
|
MOVE saveMode(A3),D1 ; get the current mode
|
||
|
MOVE D1,csMode(A2) ; force current mode, just in case for ChkPage
|
||
|
BSR.S ChkMode ; convert to depth in D1
|
||
|
; (assume current mode ok - we set it, after all)
|
||
|
MOVE.W csPage(A2),D0 ; get the requested page
|
||
|
CMP #0,D0 ; only page 0 is legal
|
||
|
BNE StatBad ; => no, just return
|
||
|
|
||
|
MOVE.L saveBaseAddr(A3),csBaseAddr(A2) ; return the base address
|
||
|
|
||
|
BRA StatGood ; => return no error
|
||
|
|
||
|
|
||
|
GetGray
|
||
|
;---------------------------------------------------------------------
|
||
|
;
|
||
|
; Return a boolean, set true if luminance mapping is on
|
||
|
;
|
||
|
;---------------------------------------------------------------------
|
||
|
|
||
|
MOVEQ #0,D1 ; set up for BFEXTU
|
||
|
GetFlagCom BFEXTU GFlags(A3){D1:1},D0 ; get the state of flag
|
||
|
MOVE.B D0,csMode(A2) ; return value
|
||
|
BRA StatGood ; => and return
|
||
|
|
||
|
|
||
|
GetInterrupt
|
||
|
;---------------------------------------------------------------------
|
||
|
;
|
||
|
; Return a boolean in csMode, set true if VBL interrupts are disabled
|
||
|
;
|
||
|
;---------------------------------------------------------------------
|
||
|
|
||
|
MOVEQ #1,D1 ; set up BFEXTU to point at IntDisFlag
|
||
|
BRA.S GetFlagCom ; and use common code
|
||
|
|
||
|
|
||
|
GetGamma
|
||
|
;---------------------------------------------------------------------
|
||
|
;
|
||
|
; Return the pointer to the current gamma table
|
||
|
;
|
||
|
;---------------------------------------------------------------------
|
||
|
|
||
|
MOVE.L saveGammaPtr(A3),csGTable(A2) ; return the pointer to the structure
|
||
|
BRA StatGood ; and return a good result
|
||
|
|
||
|
|
||
|
|
||
|
GetDefaultMode
|
||
|
;---------------------------------------------------------------------
|
||
|
;
|
||
|
; Read the card default mode from slot pRAM.
|
||
|
;
|
||
|
; A1 = Ptr to DCE
|
||
|
; A2 = Ptr to cs parameter record
|
||
|
; A3 = Ptr to private storage
|
||
|
;
|
||
|
;---------------------------------------------------------------------
|
||
|
|
||
|
WITH spBlock
|
||
|
|
||
|
;
|
||
|
; set up a slot parameter block on the stack
|
||
|
;
|
||
|
|
||
|
SUBA #spBlockSize,SP ; make an slot parameter block on stack
|
||
|
MOVE.L SP,A0 ; get pointer to parm block now
|
||
|
MOVE.B dCtlSlot(A1),spSlot(A0) ; put slot in pBlock
|
||
|
CLR.B spExtDev(A0) ; external device = 0
|
||
|
|
||
|
;
|
||
|
; read the slot pRAM to determine what the currently saved mode is. The first
|
||
|
; byte is the board ID, followed by the default mode. Aurora keeps the last
|
||
|
; selected video sRsrc spID in VendorUse2.
|
||
|
;
|
||
|
|
||
|
SUBA #SizesPRAMRec,SP ; allocate block for pRAM record
|
||
|
MOVE.L SP,spResult(A0) ; point to it
|
||
|
_sReadPRAMRec ; read it
|
||
|
|
||
|
MOVE.B 3(SP),csMode(A2) ; return the result
|
||
|
ADDA #SizesPRAMRec+spBlockSize,SP ; release buffer
|
||
|
BRA StatGood ;
|
||
|
|
||
|
ENDWITH
|
||
|
|
||
|
;---------------------------------------------------------------------
|
||
|
;
|
||
|
; Exit from control or Status.
|
||
|
;
|
||
|
;---------------------------------------------------------------------
|
||
|
|
||
|
ExitDrvr BTST #NoQueueBit,ioTrap(A0) ; no queue bit set?
|
||
|
BEQ.S GoIODone ; => no, not immediate
|
||
|
RTS ; otherwise, it was an immediate call
|
||
|
|
||
|
GoIODone MOVE.L JIODone,A0 ; get the IODone address
|
||
|
JMP (A0) ; invoke it
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
;=====================================================================
|
||
|
;
|
||
|
; Utilities
|
||
|
;
|
||
|
;=====================================================================
|
||
|
|
||
|
;---------------------------------------------------------------------
|
||
|
;
|
||
|
; ChkMode
|
||
|
;
|
||
|
; Verifies the requested mode is legal. Converts spID in D1 into
|
||
|
; zero-based mode number since lots of people want it that way.
|
||
|
;
|
||
|
; <-> D1: Mode
|
||
|
; -> A3: Pointer to driver privates
|
||
|
;
|
||
|
; All registers preserved
|
||
|
;
|
||
|
; Returns EQ if mode is valid.
|
||
|
;
|
||
|
|
||
|
ChkMode
|
||
|
MOVEM.L D0/D2,-(SP) ; save regs
|
||
|
|
||
|
SUB.B #FirstVidMode,D1 ; make it zero based
|
||
|
MOVE #FourthVidMode-FirstVidMode,D2 ; the greatest possible screen depth's number
|
||
|
|
||
|
BigTest
|
||
|
MOVE.W saveID(A3),D0 ; get the monitor type
|
||
|
|
||
|
CMP #SEId,D0 ; is it the SE display?
|
||
|
BEQ.S UpTo3 ;
|
||
|
|
||
|
CMP #GSId,D0 ; is it the GS display?
|
||
|
BEQ.S UpTo3 ;
|
||
|
|
||
|
CMP #HRId,D0 ; is it the Mac II display?
|
||
|
BEQ.S Speed ; if so then adjust for speed
|
||
|
|
||
|
; must be a portrait display, which doesn't have 8-bit/pixel
|
||
|
|
||
|
SUBQ #1,D2 ;
|
||
|
|
||
|
Speed BTST #Is16,GFlags(A3) ; if this a 16MHz processor
|
||
|
BEQ.S UpTo3
|
||
|
SUBQ #1,D2 ; 16MHz HR and FP have one less mode
|
||
|
|
||
|
UpTo3
|
||
|
CMP D2,D1 ; is it too big?
|
||
|
BGT.S ModeBad ; yes, so return
|
||
|
|
||
|
ModeOK CMP.W D1,D1 ; get EQ
|
||
|
ModeBad
|
||
|
MOVEM.L (SP)+,D0/D2 ; restore trashed regs
|
||
|
RTS ; EQ if valid depth
|
||
|
|
||
|
|
||
|
|
||
|
;---------------------------------------------------------------------
|
||
|
;
|
||
|
; Wait for vertical blanking.
|
||
|
;
|
||
|
; A1 = DCE POINTER
|
||
|
;---------------------------------------------------------------------
|
||
|
|
||
|
WaitVSync
|
||
|
|
||
|
MOVEM.L A0/D0,-(SP) ; save work registers
|
||
|
MOVE.W SR,-(SP) ; preserve the status register <2>
|
||
|
MOVEQ #7,D0 ; get mask in D0 <2>
|
||
|
AND.B (SP),D0 ; get the interrupt level <2>
|
||
|
SUBQ.B #2,D0 ; <2>
|
||
|
BGE.S @OK ; if ≥, then don't change <2>
|
||
|
ORI.W #$0200,SR ; raise above level-2 <2>
|
||
|
ANDI.W #$FAFF,SR ; make it level-2 <2>
|
||
|
@OK
|
||
|
|
||
|
MOVE.L RBV,A0 ; point to RBV
|
||
|
ADDA #RvSInt,A0 ; point to interrupt register
|
||
|
|
||
|
@0 MOVE.B (A0),D0 ; Read the Vert-Sync state,
|
||
|
BTST #6,D0 ; and test it.
|
||
|
BEQ.S @0 ; Repeat until it goes high
|
||
|
;
|
||
|
@1 MOVE.B (A0),D0 ; Read the Vert-Sync state,
|
||
|
BTST #6,D0 ; and test it.
|
||
|
BNE.S @1 ; Repeat until it goes low
|
||
|
|
||
|
MOVE (SP)+,SR ; re-enable cursor interrupts
|
||
|
MOVEM.L (SP)+,A0/D0 ; restore work registers
|
||
|
RTS
|
||
|
|
||
|
|
||
|
RBVSetDepth
|
||
|
;---------------------------------------------------------------------
|
||
|
; SetDepth sets the RBV depth, and returns the frame buffer base
|
||
|
; in driver privates
|
||
|
; D1 contains the spID of the depth
|
||
|
; A2 = parameter block pointer
|
||
|
; A3 = dCtlStorage pointer
|
||
|
; Preserves all registers
|
||
|
;---------------------------------------------------------------------
|
||
|
|
||
|
|
||
|
MOVEM.L D0/A0/A1,-(SP) ; save regs we are using <1.8>
|
||
|
|
||
|
MOVE.L RBV,A0 ; point to RBV base
|
||
|
ADDA #RvMonP,A0 ; get the monitor control register
|
||
|
MOVE.B D1,(A0) ; set the mode
|
||
|
|
||
|
MOVE.W csMode(A2),saveMode(A3) ; save mode number
|
||
|
MOVEA.l UnivInfoPtr,a1 ; point to the ProductInfo record <1.8>
|
||
|
ADDA.l ProductInfo.VideoInfoPtr(a1),a1 ; point to the VideoInfo record <1.8>
|
||
|
MOVE.L VideoInfo.VRAMLogAddr32(a1),saveBaseAddr(A3) ; save base address too <1.8>
|
||
|
ADD.L #defmBaseOffset,saveBaseAddr(A3) ; for correctness (it's zero!)
|
||
|
|
||
|
MOVEM.L (SP)+,D0/A0/A1 ; restore all regs <1.8>
|
||
|
RTS ; return
|
||
|
|
||
|
|
||
|
|
||
|
GrayScreen
|
||
|
;---------------------------------------------------------------------
|
||
|
;
|
||
|
; Fill the screen with a 50% dithered gray pattern. To have gotten here
|
||
|
; we must have had a valid display connected, so there are not tests
|
||
|
; for inactive displays here.
|
||
|
|
||
|
; A3 = driver private storage
|
||
|
;
|
||
|
; All registers are preserved
|
||
|
;
|
||
|
|
||
|
MOVEM.L D0-D3/A0-A1,-(SP) ; save all registers
|
||
|
|
||
|
MOVE.W saveID(A3),D0 ; get the current monitor type
|
||
|
|
||
|
LEA Pats,A1 ; get a pointer to the pattern table
|
||
|
MOVE.L (A1,D1*4),D3 ; D2 = the proper pattern
|
||
|
|
||
|
CMP #GSId,D0 ; is it mod'd GS display
|
||
|
BNE.S @1 ;
|
||
|
LEA GSParms,A1 ;
|
||
|
BRA.S Blast2 ;
|
||
|
@1 CMP #HRId,D0 ; is it Mac II display?
|
||
|
BNE.S @2 ;
|
||
|
LEA HRParms,A1 ;
|
||
|
BRA.S Blast2 ;
|
||
|
@2 CMP #SEId,D0 ; is it Mac SE display?
|
||
|
BNE.S @3 ;
|
||
|
LEA SEParms,A1 ;
|
||
|
BRA.S Blast2 ;
|
||
|
|
||
|
; must be a portrait display (color or monochrome) if we got here
|
||
|
@3 LEA FPParms,A1 ;
|
||
|
|
||
|
Blast2
|
||
|
MOVE.L saveBaseAddr(A3),A0 ; get the frame buffer base address
|
||
|
MOVE.W (A1),D0 ; get the # of rows
|
||
|
@NxtRow
|
||
|
MOVE.W 2(A1,D1*2),D2 ; get the # of longs/row
|
||
|
@NxtLong MOVE.L D3,(A0)+ ; write gray
|
||
|
DBRA D2,@NxtLong ; for each scanline
|
||
|
NOT.L D3 ; invert pattern on next row
|
||
|
DBRA D0,@NxtRow ; for each row
|
||
|
|
||
|
MOVEM.L (SP)+,D0-D3/A0-A1 ; restore registers
|
||
|
RTS
|
||
|
|
||
|
|
||
|
Pats DC.L OneBitGray,TwoBitGray,FourBitGray,EightBitGray
|
||
|
|
||
|
;
|
||
|
; some simple screen size parameters. The first number is the number of scanlines to
|
||
|
; erase for each mode. The next four numbers are the (decremented for DBRA) rowlongs
|
||
|
; per scanline values for each depth.
|
||
|
;
|
||
|
|
||
|
FPParms DC.W defmBounds_BFP-1,(OBMFPRB/4)-1,(TBMFPRB/4)-1,(FBMFPRB/4)-1
|
||
|
GSParms DC.W defmBounds_BGS-1,(OBMGSRB/4)-1,(TBMGSRB/4)-1,(FBMGSRB/4)-1,(EBMGSRB/4)-1
|
||
|
HRParms DC.W defmBounds_BHR-1,(OBMHRRB/4)-1,(TBMHRRB/4)-1,(FBMHRRB/4)-1,(EBMHRRB/4)-1
|
||
|
SEParms DC.W defmBounds_BSE-1,(OBMSERB/4)-1,(TBMSERB/4)-1,(FBMSERB/4)-1,(EBMSERB/4)-1
|
||
|
|
||
|
|
||
|
;-------------------------------------------------------------
|
||
|
; The Interrupt handler for Cobra board
|
||
|
;-------------------------------------------------------------
|
||
|
; The interrupt handler for the Cobra internal video board.
|
||
|
;
|
||
|
; There's a fairly serious bug in the RBV design. The interrupt line for slot zero is not
|
||
|
; clearable in software. Rather, it clears itself automatically. Unfortunately, the time
|
||
|
; interval that this signal is presented is quite long - the entire duration of the vertical
|
||
|
; sync pulse (3 scanlines!). The slot interrupt handler is level (rather than edge) sensitive,
|
||
|
; therefore, this interrupt handling routine is repeatedly called during the vBlank period.
|
||
|
; To correct this problem, this interrupt handler calls the slot interrupt task queue, then
|
||
|
; tests to see if the interrupt state is still active. If it is, then the handler masks the
|
||
|
; interrupt from slot zero, and sets a Time manager event to re-enable the interrupts after
|
||
|
; two milleseconds. By this time, we are back in active video, so the re-calling problem is
|
||
|
; taken care of.
|
||
|
;
|
||
|
; On entry A1 contains the pointer to the driver's private storage
|
||
|
; D0-D3/A0-A3 have been preserved.
|
||
|
|
||
|
|
||
|
BeginIH
|
||
|
|
||
|
MOVE.L A1,-(SP) ; save pointer to privates
|
||
|
|
||
|
CLR.W D0 ; set slot zero in D0
|
||
|
|
||
|
MOVE.L JVBLTask,A0 ; call the VBL task manager
|
||
|
JSR (A0) ; with slot # in D0
|
||
|
|
||
|
MOVE.L (SP)+,A1 ; restore A1
|
||
|
|
||
|
MOVE.L RBV,A0 ; get the RBV base address
|
||
|
BTST #6,RvSInt(A0) ; test the slot zero interrupt state
|
||
|
BNE.S @Done ; if clear, then video is out of the sync period.
|
||
|
|
||
|
MOVE.B #$40,RvSEnb(A0) ; set slot 0 interrupt disabled (slot 0 bit+set/clear to 0) <1.3>
|
||
|
LEA TTask(A1),A0 ; get the time manager task pointer
|
||
|
MOVEQ #2,D0 ; delay for 2 milleseconds
|
||
|
MOVE.L jPrimeTime,A1 ; point straight at the Time Manager dispatch vector
|
||
|
JSR (A1) ; start the delay going
|
||
|
@Done
|
||
|
MOVEQ #1,D0 ; signal that int was serviced
|
||
|
RTS ; and return to caller
|
||
|
|
||
|
;
|
||
|
; This is the time manager task. It was only posted if the VBL task queue for the internal video
|
||
|
; finished before the end of vSync. In this case, the slot 0 interrupts have been disabled.
|
||
|
; This routine turns the interrupts back on.
|
||
|
;
|
||
|
|
||
|
TimeHandler MOVE.L RBV,A0 ;
|
||
|
MOVE.B #$C0,RvSEnb(a0) ; re-enable the slot interrupt
|
||
|
RTS
|
||
|
|
||
|
END
|