mirror of
https://github.com/elliotnunn/boot3.git
synced 2024-06-09 02:29:27 +00:00
5b0f0cc134
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included. The Tools directory, containing mostly junk, is also excluded.
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 |