mac-rom/DeclData/DeclVideo/DAFB/DAFBDriver.a

3399 lines
129 KiB
Plaintext

;
; File: DAFBDriver.a
;
; Contains: This file contains the video driver for use by the Macintosh
; OS for the DAFB hardware.
;
; Written by: David Fung/Mike Puckett
;
; Copyright: © 1990-1993 by Apple Computer, Inc. All rights reserved.
;
; Change History (most recent first):
;
; <SM7> 08-03-93 jmp Changed the reference names of the multiscan display constants
; to their new names.
; <SM6> 11/5/92 SWC Changed VideoEqu.a->Video.a and ShutdownEqu.a->Shutdown.a.
; <SM5> 11/2/92 kc Don't include SonicEqu.a.
; <SM4> 10-29-92 jmp (jmp,H26) Fixed a branching problem in the PageMode
; enabling/disabling code in VidOpen.
; <SM3> 10-17-92 jmp (jmp,H25) Fixed a subtle bug that would only occur when the CPU
; was set up to be in 24-bit mode -- the problem had to do with my
; putting the machine in 32-bit mode and calling a slot manager
; trap (_sGetBlock) that ended up allocating 32-bit memory in a
; 24-bit System heap. OoopsÉ.
; <SM2> 10-13-92 jmp (jmp,H24) Fixed a problem in SetDepth where I was clearing the
; ClkSel bit in the DAFBClkCfg register. For the NSC-8534 this
; bit must be a one, and for the NSC-8531 it must be a zero.
; Also, added a line of code that got ÒlostÓ from the Zydeco
; sources.
; <SM1> 10/6/92 GDW New location for ROMLink tool.
; ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
; Pre-ROMLink comments begin here.
; ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
; <SM9> 09-29-92 jmp (jmp,H23) Added about a 1-µSec delay between SetEntries R-G-B
; writes to the Antelope CLUT/DAC (i.e., unlike the Brooktree and
; AMD CLUT/DACs, the Antelope parts donÕt use dual-ported RAM
; internally).
; (jmp,H22) The TimingAdj register wasnÕt being set up properly in
; PAL 16bpp FF/ST with Antelope parts. Fixed this.
; (jmp,H21) Added more support for the Antelope (AT&T/Sierra)
; CLUT/DAC used on Wombat/WLCD.
; <SM8> 09-03-92 jmp (jmp,H20) Added initial support for the AT&T CLUT/DAC to be used
; in Wombat/WLCD systems.
; <SM7> 07-14-92 jmp (jmp,H18) Fixed a minor bug in ChkMode where I was allowing
; 32bpp to be set on Rubik for a WombatDAFB.
; (jmp,H17) Added in support to make the DAFBDriver function
; correctly among Spike, Eclipse, Zydeco, and all Wombat/WLCD
; CPUs.
; (jmp,H16) Added more Wombat support as well as continued with
; general optimizations.
; (jmp,H15) Tightened up the Wombat TimingAdj adjustment table
; (used bytes instead of words).
; (jmp,H14) Added first-pass support for the Wombat version of
; DAFB.
; <SM6> 6/18/92 KW (jmp,H13) Eliminated yet even more of the old DAFBVidParams
; fields, so I adjusted the code accordingly.
; <SM5> 6/4/92 KW (jmp,H12) Fixed a problem where I wasnÕt setting up the timing
; adjust register in the Brooktree DAC case. Oops! (jmp,H11) Made
; the code that deals with the DAFB vidParams ÒsmarterÓ due my
; compacting vidParams tables. This kind of work will continue
; throughout Wombat development. (jmp,H10) Cleaned up the
; interrupt handler a little, cleaned up WaitVSync a little, fixed
; the Òlittle table of countsÓ problem from Zydeco, etcÉ.
; <SM4> 5/16/92 kc Roll in Horror Changes. Comments follow:
; <H9> 02/20/92 jmp (jmp,Z51) Fixed a problem in the SetDepth where I wasnÕt always
; selecting the correct clock. This problem surfaced due to a
; change in the AC824A (aka AC823).
; <H8> 01/22/92 jmp (jmp,Z50) Updated the original ÒNo ConnectÓ code to take full
; advantage of the newly-defined extended sense codes. Changed
; the name from ÒNoConnectÓ to ÒAltSense.Ó
; <H7> 01/11/92 jmp Added rudimentary support for the newly-defined extended sense
; codes.
; <H6> 12/17/91 jmp Eliminated some code in GrayScreen that handled base addresses
; that moved across depths, as it is no longer needed.
; <H5> 11/25/91 jmp The vidParams moved from the functional to the board sRsrc to
; save space -- updated the driver accordingly.
; <H4> 11/12/91 jmp Quit forcing the bitdepth back to 1bpp in SetDefaultMode.
; <H3> 11/05/91 jmp Added support for 19Ó Displays.
; <3> 3/31/92 JSM Rolled this file into Reality.
; <2> 2/14/92 kc Fix "Label defined on next word boundary" assembler warning.
; <50> 01/20/92 jmp Updated the original ÒNo ConnectÓ code to take full advantage of
; the newly-defined extended sense codes. Changed the name from
; ÒNoConnectÓ to ÒAltSense.Ó
; <49> 01/09/92 jmp Added rudimentary support for the newly-defined extended sense
; codes.
; <48> 12/17/91 jmp Eliminated some code in GrayScreen that handled base addresses
; that moved across depths, as it is no longer needed.
; <47> 11/08/91 jmp Quit forcing the bitdepth back to 1bpp in SetDefaultMode.
; <46> 11/05/91 jmp Added preliminary support for 19Ó Displays.
; <45> 10/16/91 jmp Added a check in the video open routine that determines whether
; video (i.e., sync) is currently on or not. If itÕs off, then we
; now turn it back on. This was added to support turning video
; back on immediately in the event that the video driver is closed
; and needs to be opened again during ÒnormalÓ operation of the
; CPU.
; <44> 09/17/91 jmp Needed to ensure that the 100 Mhz clock was being shut off when
; Ògrounding outÓ the ECL clock signals.
; <43> 09/17/91 jmp Added support for Ògrounding outÓ the ECL clock signals in
; software using the AMD-ACDC for Zydeco/Spike33 CPUs.
; <42> 09/13/91 jmp Added support for 16pp on Rubik displays when only 512K of vRAM
; is around in preparation for Spike33s.
; <41> 8/9/91 jmp Just cleaned up some comments and line-spacings.
; <40> 8/9/91 jmp When I removed the NeedsGoodBye control call, I didnÕt remove
; the extra check. So, I removed that now.
; <39> 8/9/91 jmp Fixed a VERY minor bug in VidOpen where I was using D0 instead
; of D2 to get the monID.
; <38> 8/9/91 jmp Added support to fix a problem with NTSC & PAL family modes
; where changing the amount of vRAM didnÕt cause PrimaryInit to
; re-validate the SP_LastConfig pRAM byte. Also, enabled/disabled
; PageMode in VidOpen depending on the state of pageMode pRAM bit.
; <37> 8/7/91 jmp Added 16bpp support for all displays.
; <36> 7/30/91 jmp Removed the support for the NeedsGoodBye control call.
; <35> 7/29/91 jmp Started validating the mode passed into the SetDefaultMode call;
; none of our previous video drivers have done this. Also, fixed
; the gamma-correction code used on depth switches so that
; mono-only devices are only corrected on the blue channel (as
; they should be).
; <34> 7/13/91 jmp Added routines to extend the factory burn-in no-connect
; detection routines so that ANY display supported by DAFB could
; be used.
; <33> 7/11/91 jmp God, I hate last minute code changes!
; <32> 7/11/91 jmp Yet even more intelligent page-mode handling coded was added.
; <31> 7/11/91 jmp Added even more intelligent code for enabling & disabling page
; mode.
; <30> 7/11/91 jmp Added code to more intelligently handle the enabling & disabling
; of page mode.
; ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
; Pre-Zydeco ROM comments begin here.
; ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
; <29> 6/29/91 jmp Added support for the alternate AC842A-compatible timing adjust,
; horizontal active line, and horizontal front porch DAFB
; parameters.
; <28> 6/27/91 jmp Fixed the Set16bpp call so that it now supports the case where
; 16bpp mode is always non-blocked.
; <27> 6/26/91 jmp Rewrote the ACDC-whacking code to be more AC842A (AMD) friendly.
; <26> 6/25/91 jmp Fixed a problem in 16bpp DirectSetEntries and fixed the problem
; with 16bpp not sticking.
; <25> 6/24/91 jmp Added support for 16bpp Vesuvio & RGB Portrait displays.
; <24> 6/17/91 jmp Fixed a type in the Òmemory leakÓ fix in SetGamma that I ÒfixedÓ
; last time.
; <23> 6/10/91 jmp Fixed a Òmemory leakÓ bug in SetGamma when changing the size of
; the current gamma table (i.e., from size 3 to 1, or vice-versa).
; This caused programs like MacroMind Director 2.0 to get
; out-of-memory errors after playing movies that cycled gamma
; (e.g., for screen fades).
; <22> 6/7/91 jmp Fixed a bug in SetEntries where I had the sense of my
; error-checking backwards. This caused programs like Color
; Studio 1.11 & QuarkXPress 3.0 to hose the System Palette when
; setting a single entry.
; <21> 5/25/91 jmp The close routine was NOT 32-bit clean, and bus-errored when
; called. So, I fixed it.
; <20> 5/24/91 jmp Added support for enabling/disabling sync-on-green.
; <19> 5/22/91 jmp Went back to the more forgiving gamma correction strategy so
; that the gamma tables can be shared among the various built-in
; videos. This is okay, for now, since all the built-in videos
; have similar DACs.
; <18> 5/15/91 jmp WasnÕt cleaning up the stack on exit from GetEntries input
; errors. VidReset wanÕt passing the right value to DAFBSetDepth
; (i.e., indexed mode value vs. bpp value). And GetPage wasnÕt
; range-checking the input mode properly.
; <17> 5/10/91 jmp Due to the fact that interrupt status registers are NOT inverted
; as originally assumed, the WaitVSync code could have hung
; forever in some cases; fixed that problem. In Get/SetEntries
; fixed the fact that some apps are NOT 32-bit clean; i.e., they
; pass in a 24-bit CTabHandleÕs MasterPointer as a Pointer.
; Optimizations: Tightened up the WaitVSync code; changed several
; Move.bÕs and Move.wÕs to MoveqÕs where applicable. Used scaling
; in the VidStatus jumptable (i.e., like the VidCtl jumptable).
; Added SuperVGA support. Now check for 25 vs. 33 MHz CPU
; operation the new, better way. Code reveiw changes: Cleaned up
; the error-handling code in VidOpen; tightened up the code in
; VidOpen that builds a linear gamma table; cleaned up the
; ST-corrected screen baseAddr code; and swapped to 32-bit
; addressing mode in VidClose in order to idle DAFB.
; <16> 4/23/91 jmp Fixed a bug in SetVidMode where I was trashing A0. Also, quit
; jumping thru jSwapMMU and started using _SwapMMUMode, except in
; the interrupt handler. Started using monIDs instead of spIDs
; where possible for config testing -- less compares. Fixed a bug
; in ChkMode where I was using Cmp.wÕs instead of Cmp.bÕs.
; <15> 4/19/91 jmp The gamma correction code was doing very bad things. First, it
; was always allowing TFB-style tables (i.e., non-hardware
; specific tables) to pass through. Second, it was building
; linear ramps backwards. In SetVidMode, I added 3-channel gamma
; correction code due to the 6500¡K simulation for Vesuvio &
; GoldFish. I also fixed a bug in SetGamm where we were not
; setting the new gamma table when in direct mode. Finally, I now
; synthesize a linear gamma table on the fly in VidOpen if a gamma
; directory doesnÕt exist (i.e., for NTSC, PAL, and VGA).
; <14> 4/3/91 jmp Moved the Bsr to WaitVSync to just before the DAFBReset sequence
; in DAFBSetDepth. This reduces the problem with the display
; ÒjumpingÓ when switching bit-depths. The most notable offender
; is MacsBug when stepping.
; <13> 4/1/91 jmp Removed support for DAFB 1.
; <12> 3/25/91 jmp I was not saving the monitor ID at open time for
; gamma-correction checking. I was also not writing to the
; correct guns on mono-only displays (i.e., I was clearing red,
; setting green, and not touching blue; should have been clearing
; red & green, and setting blue). Fixed a bug in three-channel
; direct CLUTs (wasnÕt actually pointing to blue). Fixed a bug in
; indexed SetEntries where I was jumping into the RBV video driver
; due to a common label.
; <11> 3/18/91 jmp Fixed ÒfalseÓ tops and bottoms in the convolved screen-clearing
; code. Fixed a problem in SetEntries where A0 was potentially
; being trashed.
; <10> 3/4/91 jmp Fixed 1bpp Rubik Display problem (i.e., first line of vRam not
; being cleared).
; <9> 2/25/91 jmp Changed the interrupt handling code to use CrsrLine instead of
; VBL because CrsrLine is programmable. Added a Bsr to
; DAFBWaitVSync in DAFBDirectClutSet. SetEntries was not 32-bit
; clear as we were not StripAddressÕing the csTable pointer.
; <8> 2/15/91 jmp Fixed bug in SetEntries where an input error would have
; corrupted the stack (i.e., not popping saved register off
; stack). Fixed screen graying code to work properly with the
; convolved modes only supporting 4/8bpp. Conditionalized so that
; when new DAFBs are around, the coding effort will be minimal.
; Added check for 33 vs. 25 Mhz operation.
; <7> 2/10/91 jmp Fixed screen base address calculations (for ST modes). Fixed
; the mode validation (ChkMode) code.
; <6> 2/3/91 jmp Updated GrayScreen for NTSC and PAL ST modes (including blacking
; around the sides).
; <5> 1/30/91 jmp Just replaced the in-line reset instructions with the DAFBReset
; macro defined in RBVDepVideoEqu.a.
; <4> 1/24/91 jmp Finished a first stab at DAFBGetEntries.
; <3> 1/21/91 jmp Incremental change -- fixed/added the IsMono code.
; <2> 1/14/91 DAF Added file for first time, but needed to adjust the comment!
; <1> 1/14/91 DAF First checked in.
;
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 '_sDAFBDriver'
BLANKS ON
STRING ASIS
MACHINE MC68020
; This is device storage which is stored in the dCtlStorage field of the AuxDCE.
DAFBVidPrivates RECORD 0
saveBaseAddr DS.L 1 ; the screen base address (NOT ST corrected!)
saveScreenBase DS.L 1 ; ST corrected version of saveBaseAddr.
saveSQElPtr DS.L 1 ; the SQ element pointer (for _SIntRemove)
saveGammaPtr DS.L 1 ; the pointer to the Gamma correction table
saveGamDispPtr DS.L 1 ; the pointer to the Gamma block
saveVDACBase DS.L 1 ; the base addr of the VDAC
saveDAFBBase DS.L 1 ; the base addr of the DAFB
saveVidPtr DS.L 1 ; pointer to a big block of DAFB video parameters
GFlags DS.B 1 ; flags word (in hi-byte)
wombatFlag Ds.b 1 ; (hidden WombatDAFB flag)
has16bppACDC Ds.b 1 ; true if AC842A is around
pageModeSet Ds.b 1 ; true if the pRam PageMode enable bit is set
saveMode DS.W 1 ; the current mode setting (in lo-byte)
saveMonID DS.W 1 ; monitor type ID (in lo-byte)
saveSlotId DS.B 1 ; spID of video sRsrc
hasLin16bppCLUT Ds.b 1 ; true if AC842A is Antelope
DAFBVidPrivSize EQU *
ENDR
LDAFBDriver MAIN EXPORT
;-------------------------------------------------------------------
; Video Driver Header
;-------------------------------------------------------------------
;
DAFBDrvr
DC.W $4C00 ; ctl,status,needsLock
DC.W 0,0,0 ; not an ornament
; Entry point offset table
DC.W DAFBVidOpen-DAFBDrvr ; open routine
DC.W DAFBDrvr-DAFBDrvr ; no prime in normal video drivers
DC.W DAFBVidCtl-DAFBDrvr ; control
DC.W DAFBVidStatus-DAFBDrvr ; status
DC.W DAFBVidClose-DAFBDrvr ; close
STRING Pascal
DAFBVidTitle
DC.B '.Display_Video_Apple_DAFB'
ALIGN 2 ; make sure we're aligned
DC.W CurDAFBDrvrVersion ; current version
STRING ASIS
;
; This table simply contains the zero-based maximum index value for each of the depths. It is
; set up to be indexed via the modeID. The DAFBXClutTbl is for supporting 16bpp-capable
; sResources.
;
DAFBClutTbl Dc.b $01,$03,$0F,$FF,$FF
DAFBXClutTbl Dc.b $01,$03,$0F,$FF,$1F,$FF
;
; These are the bit patterns for grays in each depth, except the last one which is the black
; Òhalf-patternÓ in 32-bit/pixel mode. The DAFBXPats are for supporting 16bpp-capable
; sResources.
DAFBPats Dc.l OneBitGray,TwoBitGray,FourBitGray,EightBitGray,ThirtyTwoBitGray
DAFBXPats Dc.l OneBitGray,TwoBitGray,FourBitGray,EightBitGray,SixteenBitGray,ThirtyTwoBitGray
;
; Normally, if no monitor is detected on boot, PrimaryInit just shuts video down. However,
; if the no-connect pRam code is valid, then we things up as if the monitor code
; specified in pRam were actually connected. The DAFBMonIDs table (below) is composed
; of the valid monitor IDs supported by DAFB.
;
DAFBMonIDs Dc.w MonIDSEnd-MonIDsBegin-2
MonIDsBegin
Dc.b indexedSenseRGB2P,indexedSenseFP,indexedSenseRubik,indexedSense2P
Dc.b indexedSenseNTSC,indexedSenseRGBFP,indexedSenseHR
Dc.b extendedSensePALBox,extendedSenseNTSC,extendedSenseVGA
Dc.b extendedSenseLP,extendedSensePAL,extendedSense19
Dc.b 0
MonIDSEnd
;
; Because Wombat uses a different clock chip, the TimingAdj value for Spike/Eclipse/Zydeco
; doesnÕt work on Wombat. However, the TimingAdj adjustment value is simple to compute
; based on the pixel depth and the clock divider. So, the table represents the value to
; to add to TimingAdj per pixel depth per clock divider. The zeros in the table are
; unused place holders.
;
DAFBWombatTimingAdjTbl
Dc.w 32,16,8,4,2,1 ; PixClk/1
DAFBWombatTimingEntry
Dc.w 16, 8,4,2,1,0 ; PixClk/2
Dc.w 8, 4,2,1,0,0 ; PixClk/4
DAFBWombatTSize Equ DAFBWombatTimingEntry-DAFBWombatTimingAdjTbl
DAFBAntelopeTbl Dc.w 5,2,1 ; PixClk/1,PixClk/2,PixClk/4 TimingAdj,HAL,HFP adjustments.
**********************************************************************
*
* DAFBVidOpen allocates private storage for the device in the AuxDCE and locks
* it down for perpetuity. Also, install the interrupt handler and enable
* the interrupts.
*
* Entry: A0 = param block pointer
* A1 = AuxDCE pointer
*
* Locals: A3 = pointer to private storage
*
* A4/D2/D3 used as scratch
*
**********************************************************************
WITH VDPageInfo,SlotIntQElement,DAFBVidPrivates
DAFBVidOpen
;
; Allocate private storage (since block is CLEAR, GFlags are zeroed) and get
; a pointer to it in A3
;
MOVEQ #DAFBVidPrivSize,D0 ; get size of parameters
_ResrvMem ,SYS ; make room as low as possible
MOVEQ #DAFBVidPrivSize,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 AuxDCE
_HLock ; and lock it down forever
MOVE.L (A0),D0 ; get a pointer to it
_StripAddress ; clean it up
MOVE.L D0,A3 ; get pointer to privates in A3
;
; Remember the VDAC and DAFB base addresses since they're hard to look up.
;
WITH ProductInfo,DecoderInfo,VideoInfo
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
MOVE.L DAFBAddr(A0),saveDAFBBase(A3) ; save DAFB's base too
;
; Remember the frame buffer base as well. The Open call doesn't set the video mode
; or page, but SetMode will based on this value (a little later).
;
MOVE.L UnivInfoPtr,A0
ADDA.L VideoInfoPtr(A0),A0 ; point to the VideoInfo record
MOVE.L VRAMLogAddr32(A0),saveBaseAddr(A3) ; save base address too
ENDWITH
;
; 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 @OpError2 ; if not allocated, return bad
MOVE.L A0,saveSQElPtr(A3) ; save the SQ element pointer.
Moveq #true32b,D0 ; Say we want to be in 32-bit mode.
_SwapMMUMode ; Do swap.
Move.l saveDAFBBase(A3),A2 ; Get DAFBÕs base address into A2.
DAFBUnIdle ; Make sure DAFB is not idle.
_SwapMMUMode ; Swap back.
BSR DAFBEnableVGuts ; Enable VBL interrupts.
BNE @OpError2 ;
;
; Load the default gamma table from the slot resource list.
;
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
CLR.B spExtDev(A0) ;
_sRsrcInfo ; get the spsPointer
BNE @OpError3 ; if failed, then quit.
MOVE.B #sGammaDir,spID(A0) ; look for the gamma directory
_sFindStruct ; get that baby
BNE.S @DoLinear ; if failed, then do linear
MOVE.B #128,spID(A0) ; get the default gamma table, (always 128)
_sGetBlock ; we can use this since we want it on the sys heap
BNE.S @DoLinear ; if failed, then do linear
; Skip over gamma header.
MOVE.L spResult(A0),A0 ; point to head of the block
MOVE.L A0,saveGamDispPtr(A3) ; save the ptr to the gamma block
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 #0,D0 ; round it off
MOVE.L D0,saveGammaPtr(A3) ; put it in private storage
Bra.s @VidParams ; Jump around linear code.
;
; Build a linear default gamma table if necessary.
;
@DoLinear
Moveq #gFormulaData,D0 ; Get gamma table header size.
Add #256,D0 ; Add in one-byte per entry.
_NewPtr ,SYS,CLEAR ; Clear it.
Bne @OpError3 ; If failed, quit.
Move.l A0,saveGamDispPtr(A3) ; Save head of gamma table for disposal.
Move.l A0,saveGammaPtr(A3) ; Head and top are same here.
Move.w #drHwDAFB,gType(A0) ; Set up gType.
Move.w #1,gChanCnt(A0) ; Set up gChanCnt.
Move.w #256,gDataCnt(A0) ; Set up gDataCnt.
Move.w #8,gDataWidth(A0) ; Set up gDataWidth.
Adda #gFormulaData+256,A0 ; Point to end of data table.
Move.w #255,D0 ; Set up loop counter.
@Loop Move.b D0,-(A0) ; Write out value.
Dbra D0,@Loop ; Loop.
;
; Get a pointer to the video hardware setup parameter block. Use this functional spID's spsPointer
; found above in the gamma section.
;
With DAFBVidParams
@VidParams
Move.l Sp,A0 ; Point to the spBlock on the stack.
Clr.w spID(A0) ; Start looking at spID 0, no external devices.
Clr.b spTBMask(A0) ; Only look for the board sRsrc.
Move.w #catBoard,spCategory(A0) ; Look for: catBoard,
Move.w #typBoard,spCType(A0) ; typBoard,
Clr.w spDrvrSW(A0) ; 0,
Clr.w spDrvrHW(A0) ; 0.
Clr.l spParamData(A0) ; (The board sRsrc must be enabled.)
Bset #foneslot,spParamData+3(A0) ; Limit search to slot $0.
_GetTypeSRsrc ; Get the spsPointer.
Bne @OpError4 ; If failed, quit.
MOVE.B #sVidParmDir,spID(A0) ; look for the video parameters dir
_sFindStruct ; Try to load it.
Bne @OpError4 ; If failed, quit.
Move.l saveDAFBBase(A3),A4 ; Get DAFBBase into A4.
Move.b dCtlSlotId(A1),D1 ; Get the appropriate sRsrcID into D1.
Moveq #true32b,D0 ; Set up to flip into 32-bit addressing mode.
_SwapMMUMode ; Do flip.
Move.b D0,-(Sp) ; Save previous addressing mode.
Move.l DAFBFlags(A4),D0 ; Get the DAFBFlags into D0.
Btst #RadiusTPDBit,D0 ; If we donÕt have a RadiusTPD,
Beq.s @GetParams ; then just go on.
Btst #RadiusDevType,D0 ; If we have a Radius MonoTPD,
Beq.s @SetMonoTPD ; then say so.
Move.b #pSRsrc_Vid_DAFB_2PRdRGB,D1 ; Otherwise, say weÕve gotÉ
Bra.s @GetParams ; Éa ColorTPD.
@SetMonoTPD Move.b #pSRsrc_Vid_DAFB_2PRdMono,D1 ;
@GetParams Move.b (Sp)+,D0 ; Set up to restore previous addressing mode.
_SwapMMUMode ; Do flip.
MOVE.B D1,spID(A0) ; look in the directory for this config's parameters
_sGetBlock ; Try to load it.
Bne @OpError4 ; If failed, quit.
MOVE.L spResult(A0),saveVidPtr(A3) ; get pointer to it
Move.b dCtlSlotId(A1),spID(A0) ; Set up to find the functional sRsrc.
_sRsrcInfo ; Get the spsPointer.
Bne @OpError5 ; If failed, quit.
Move.b #MinorBaseOS,spID(A0) ; Set up to get the video base offset value.
_sReadLong ; Get it.
Bne @OpError5 ; If failed, quit.
Move.l spResult(A0),D0 ; Load the vRAM base offset into D0.
Add.l D0,saveBaseAddr(A3) ; Add it to the vRAM base address.
Endwith
;
; At PrimaryInit time, we used the sense lines to determine the type of attached display. For extended
; sense displays, we just mapped them to the end of indexed-sense displays. Since the gamma-correction
; code uses the monitor ID to determine if the passed-in table is applicable, we need to know the ÒrealÓ
; monitor ID. At PrimaryInit time, we store the real monitor ID in slot pRAM. So, we extract that
; information out here. Also, it should be noted that it would actually be inappropriate for us
; to re-read the sense-lines now, in that someone could potentially change/unplug the attached
; display between PrimaryInit and VidOpen, and that would cause us all sorts of havoc.
;
With SP_Params
Move.l Sp,A0 ; Point to spBlock on the stack.
Move.b dCtlSlot(A1),spSlot(A0) ; Put slot into spBlock.
Suba #sizeSPRamRec,Sp ; Allocate an SPRam block on the stack.
Move.l Sp,spResult(A0) ; Point to it.
_SReadPRAMRec ; Read Slot PRam.
Bne @OpError6 ; If failed quit.
Moveq #0,D3 ; Clear D3.w.
Moveq #0,D2 ; Clear D2.w.
Move.b SP_Depth(Sp),D3 ; Get the mode (itÕs byte sized).
Move.b SP_MonID(Sp),D2 ; Get the monID (itÕs byte sized).
Move.b SP_Flags(Sp),D1 ; Get the flags.
Adda #sizeSPRamRec+spBlockSize,Sp ; Clean up the stack.
EndWith
;
; Do a little bookkeepingÉ
;
Move.w D3,saveMode(A3) ; Save the mode for later.
Move.w D2,saveMonID(A3) ; Save the monID for later.
Move.b dCtlSlotId(A1),saveSlotId(A3) ; Also save the spID.
Btst #spSyncOnGreen,D1 ; If weÕre not supposed to put sync on green,
Beq.s @CheckAC842A ; then just go on.
Bset #syncOnGreen,GFlags(A3) ; Otherwise, set the flag.
@CheckAC842A Btst #spHas16bppACDC,D1 ; If we donÕt have an AC842A,
Beq.s @CheckPageMode ; then go on.
Move.b #1,has16bppACDC(A3) ; Otherwise, say we do.
Btst #spHas16bppSRsrc,D1 ; If we donÕt have a 16bpp-capable sRsrc,
Beq.s @CheckPageMode ; then just go on.
Bset #has16bppSRsrc,GFlags(A3) ; Otherwise, set the flag.
@CheckPageMode Move.l saveDAFBBase(A3),A4 ; Get DAFBBase into A4 for below.
Btst #spPageMode,D1 ; If PageMode is supposed to be enabled,
Bne.s @EnablePageMode ; then say so.
Move.b #0,pageModeSet(A3) ; Otherwise, say page mode is disaabled.
Bra.s @PageModeDisabled ;
@EnablePageMode Move.b #1,pageModeSet(A3) ; Say page mode is enabled.
@PageModeDisabled
Move.b #true32b,D0 ; Set up to swap into 32-bit addressing mode.
_SwapMMuMode ; Do swap, and
Move.b D0,-(Sp) ; save the previous mode.
Move.l DAFB_Config(A4),D0 ; Read the DAFBConfig register.
Bfextu D0{dafbWrdIntBit:1},D0 ; If word-interleave is on
Bne.s @DisablePageMode ; then ALWAYS disable page mode.
Tst.b pageModeSet(A3) ; If weÕre not supposed to enable page mode,
Beq.s @DisablePageMode ; then disable it.
Moveq #1,D0 ; Otherwise, set up to enable page mode,
Bra.s @HitPageMode ; and do it.
@DisablePageMode
Moveq #0,D0 ; Set up to disable page mode, and
@HitPageMode Move.l D0,DAFB_PgMdEn(A4) ; and do it.
Move.l DAFBFlags(A4),D0 ; Get the DAFBFlags.
Btst #isWombat,D0 ; If weÕre not on a Wombat,
Beq.s @ChkCLUTType ; then just go on.
Move.b #1,wombatFlag(A3) ; Otherwise, say weÕre on a Wombat.
@ChkCLUTType Btst #wLin16Bpp,D0 ; If we donÕt have an Antelope,
Beq.s @ChkVidEnb ; then just go on.
Move.b #1,hasLin16BppCLUT(A3) ; Otherwise, say weÕve got one.
@ChkVidEnb Move.w D0,D1 ; Copy the DAFBFlags.
Move.b (Sp)+,D0 ; Set up to switch back into previous mode,
_SwapMMUMode ; and do it.
Btst #videoEnabled,D1 ; If video is still enabled,
Bne.s @CalcScrnBase ; then just go on.
Move.w saveMode(A3),D1 ; Otherwise, get the mode into D1.
Sub.w #firstVidMode,D1 ; Make it an index.
Bsr DAFBSetDepth ; Set the depth.
Bsr DAFBCalcScreenBaseAddr ; Calculate the new ST-corrected screen baseAddr.
Bsr DAFBGrayScreen ; Paint the screen gray.
Bra.s @SkipIt ; Go on.
@CalcScrnBase
Move.w #firstVidMode,saveMode(A3) ; From PrimaryInit, weÕre still at 1bpp.
Bsr DAFBCalcScreenBaseAddr ; Save the ST-corrected screen baseAddr.
@SkipIt
;
; Set GFlags to reflect monochrome-only displays.
;
Cmp.w #indexedSenseFP,saveMonID(A3) ; If this is a Mono-Only Full Page,
Beq.s @SetMonoFlags ; then say so.
Cmp.w #indexedSense2P,saveMonID(A3) ; If this is a Mono-Only Two-Page,
Beq.s @SetMonoFlags ; then say so.
Bra.s @EndMonoCheck ; Otherwise, skip.
@SetMonoFlags Bset #IsMono,GFlags(A3) ; Turn on the IsMono and
Bset #GrayFlag,GFlags(A3) ; GrayFlag flags.
@EndMonoCheck
;
; Determine the clock speed and save it. The act of reading VIAs can cause pending interrupts
; to be lost, so we want only want to do this once.
;
Tst.b wombatFlag(A3) ; If weÕre on a Wombat, then
Bne.s @WombatSpeed ; skip the Spike/Eclipse/Zydeco stuff.
Move.l VIA2,A0 ; Point to VIA2.
Btst #v2Speed,vBufB(A0) ; Test the speed register (25 vs. 33 MHz).
Bra.s @EndSpeedChk
@WombatSpeed Move.l VIA,A0 ; Point to VIA1.
Btst #vCpuId2,vBufA(A0) ; Test CPUID reg 2 (20/25 vs. 33/40 MHz).
@EndSpeedChk Bne.s @AllDone ; Leave flag clear if weÕre not going slow.
Bset #IsSlow,GFlags(A3) ; Otherwise, set it.
;
; All done!
;
@AllDone MOVEQ #noErr,D0 ; no error
@EndOpen RTS ; return
@OpError6 Adda #sizeSPRamRec,Sp ; Release the SPRam block.
@OpError5 Move.l saveVidPtr(A3),A0 ; Set up to dispose of vidParams table.
_DisposPtr ; Dispose it.
@OpError4 Move.l saveGamDispPtr(A3),A0 ; Set up to dispose of gamma table.
_DisposPtr ; Dispose it.
@OpError3 ADDA #spBlockSize,SP ; release the spBlock
@OpError2 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
BRA.S @EndOpen
ENDWITH
**********************************************************************
*
* Video Driver Control Call Handler. There are 10 standard calls:
*
* ($00) Reset (VAR mode, page: INTEGER; VAR BaseAddr: Ptr);
* ($01) KillIO
* ($02) SetMode(mode, page: INTEGER; VAR BaseAddr: Ptr);
* ($03) SetEntries (Table: Ptr; Start,Count : integer );
* ($04) SetGamma (Table : Ptr );
* ($05) GrayPage (page);
* ($06) SetGray (csMode = 0 for color, 1 for gray)
* ($07) SetInterrupt (csMode = 0 for enable, non-zero for disable);
* ($08) DirectSetEntries (Table: Ptr; Start,Count : integer );
* ($09) SetDefaultMode (csMode = mode to set);
*
* The following calls are DAFB-specific:
*
* ($80) SetSyncOnGreen(csMode = 0 for enable, non-zero for disable);
* ($81) Set16bpp(csMode = 0 for enable, non-zero for disable);
* ($82) SetPageMode(csMode = 0 for enable, non-zero for disable);
* ($83) SetAltSense(csMode = byte 0 is sense code, byte 1 is type);
*
* Entry: A0 = param block pointer
* A1 = AuxDCE pointer
* Uses: A2 = cs parameters (ie. A2 <- csParam(A0)) (must be preserved)
* A3 = ptr to our privates/scrarch (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É
;
DAFBVidCtl
MOVEM.L A0/A1,-(SP) ; Save exit registers.
MOVE.L csParam(A0),A2 ; A2 <- Ptr to control parameters
MOVE.L dCtlStorage(A1),A3 ; A3 <- Ptr to private storage
MOVE.L (A3),D0 ;
_StripAddress ;
MOVE.L D0,A3 ;
MOVE.W csCode(A0),D0 ; get routine selector
Cmp.w #cscSyncOnGreen,D0 ; If we got the SetSyncOnGreen call,
Beq DAFBSetSyncOnGreen ; hop to it.
Cmp.w #csc16bpp,D0 ; If we got the 16bpp call,
Beq DAFBSet16bpp ; hop to it.
Cmp.w #cscPageMode,D0 ; If we got the PageMode call,
Beq DAFBSetPageMode ; hop to it.
Cmp.w #cscAltSense,D0 ; If we got the alternate senseID call,
Beq DAFBSetAltSense ; hop to it.
CMP.W #9,D0 ; IF csCode NOT IN [0..9] THEN
BHI.S DAFBCtlBad ; Error, csCode out of bounds.
MOVE.W DAFBCtlJumpTbl(PC,D0.W*2),D0 ; Get the relative offset to the routine.
JMP DAFBCtlJumpTbl(PC,D0.W) ; GOTO the proper routine.
DAFBCtlJumpTbl
DC.W DAFBVidReset-DAFBCtlJumpTbl ; $00 => VidReset
DC.W DAFBCtlGood-DAFBCtlJumpTbl ; $01 => CtlGood (no async routines here)
DC.W DAFBSetVidMode-DAFBCtlJumpTbl ; $02 => SetVidMode
DC.W DAFBSetEntries-DAFBCtlJumpTbl ; $03 => SetEntries
DC.W DAFBSetGamma-DAFBCtlJumpTbl ; $04 => SetGamma
DC.W DAFBGrayPage-DAFBCtlJumpTbl ; $05 => GrayPage
DC.W DAFBSetGray-DAFBCtlJumpTbl ; $06 => SetGray
DC.W DAFBSetInterrupt-DAFBCtlJumpTbl ; $07 => SetInterrupt
DC.W DAFBDirectSetEntries-DAFBCtlJumpTbl ; $08 => DirectSetEntries
DC.W DAFBSetDefaultMode-DAFBCtlJumpTbl ; $09 => SetDefaultMode
DAFBCtlBad MOVEQ #controlErr,D0 ; else say we don't do this one
BRA.S DAFBCtlDone ; and return
DAFBCtlGood MOVEQ #noErr,D0 ; return no error
DAFBCtlDone MOVEM.L (SP)+,A0/A1 ; Restore Exit registers.
BRA DAFBExitDrvr
DAFBVidReset
;---------------------------------------------------------------------
;
; Reset the card to its default
;
;---------------------------------------------------------------------
WITH DAFBVidPrivates
MOVE #FirstVidMode,csMode(A2) ; return default mode
MOVE #FirstVidMode,saveMode(A3) ; remember FirstVidMode as the requested mode
MOVEQ #0,D1 ; get default depth in D1 (#firstVidMode-#firstVidMode)
MOVEQ #0,D0 ; get page in D0
MOVE D0,csPage(A2) ; return the page
BSR DAFBSetDepth ; set the depth from D1
Bsr DAFBCalcScreenBaseAddr ; Calculate the new ST-corrected screen baseAddr,
Move.l saveScreenBase(A3),csBaseAddr(A2) ; and return it.
BSR DAFBGrayScreen ; paint the screen gray
BRA.S DAFBCtlGood ; => no error
ENDWITH
DAFBSetVidMode
;---------------------------------------------------------------------
;
; Set the card to the specified mode. Only page zero is possible,
; so we need to check that the request was OK.
;
; If the card is already set to the specified mode, then do nothing.
;
;---------------------------------------------------------------------
WITH DAFBVidPrivates
MOVE.W csMode(A2),D1 ; D1 = mode
BSR DAFBChkMode ; check mode and convert
BNE.S DAFBCtlBad ; => not a valid mode
TST.W csPage(A2) ; only page zero is valid
BNE.S DAFBCtlBad ; => not a valid page
; Only set if mode has changed.
MOVE.W csMode(A2),D2 ; get the mode spID (D1 has the zero-based mode)
CMP saveMode(A3),D2 ; has the mode changed?
BEQ @ModeOK1 ; if not, then skip graying
; 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.
Movem.l A4-A6/D5-D6,-(Sp) ; Save work registers.
Move.l saveGammaPtr(A3),A0 ; Get pointer to gamma data structure.
Lea gFormulaData(A0),A4 ; Point to first gamma table.
Adda.w gFormulaSize(A0),A4 ;
Move.l A4,A5 ; Point to green data (assuming gChanCnt = 1).
Move.l A4,A6 ; Point to red data (assuming gChanCnt = 1).
Cmp.w #1,gChanCnt(A0) ; If thereÕs only one table,
Beq.s @OnlyOneTable ; then weÕre set.
Move.w gDataWidth(A0),D2 ; Get width of each entry (in bits).
Move.w gDataCnt(A0),D0 ; Get # of entries in table.
Addq #7,D2 ; Round to nearest byte.
Lsr.w #3,D2 ; Get bytes per entry.
Mulu D2,D0 ; Get size of table in bytes.
Adda.w D0,A5 ; Calc base of green (red base + D0).
Adda.w D0,A6 ; Calc baseÉ
Adda.w D0,A6 ; Éof blue (red base + D0 + D0).
@OnlyOneTable
Move.w gDataCnt(A0),D3 ; Save number of gamma entries.
MOVEQ #true32b,D0 ; flip to 32-bit addressing mode
_SwapMMUMode ;
MOVE.B D0,-(SP) ; save current addressing mode
Move.w GFlags(A3),D5 ; Get the GFlags into a convient register.
Moveq #0,D6 ; Setup the alternate GFlags register.
Btst #IsMono,D5 ; If this is not a mono-only display,
Beq.s @GetVDAC ; then just go on.
Move.l saveDAFBBase(A3),A0 ; Otherwise, get the DAFBBase into A0.
Move.l DAFBFlags(A0),D0 ; Get the DAFBFlags into D0.
Btst #RadiusTPDBit,D0 ; If this is not a RadiusTPD,
Beq.s @GetVDAC ; then just go on.
Btst #RadiusDevType,D0 ; It this is not a MonoTPD,
Bne.s @GetVDAC ; then just go on.
Bset #IsMono,D6 ; Otherwise, remember to swap green & blue.
@GetVDAC MOVE.L saveVDACBase(A3),A0 ; get the VDAC base addr
Clr.l ACDC_AddrReg(A0) ; Start at position zero in the CLUT.
ADDA #(ACDC_DataReg+3),A0 ; point to data register
MOVE.W SR,-(SP) ; preserve the status register
BSR DAFBWaitVSync ; wait for next blanking period (preserves A0)
; Write out gamma-corrected gray CLUTÉ
;
Move.w D3,D0 ; Init loop counter.
Subq #1,D0 ; Zero base it.
Lsr.w #1,D3 ; Get midpoint of table(s).
@Repeat Btst #IsMono,D6 ; If this is not a Radius MonoTPD,
Beq.s @NotRadius ; then go on.
Clr.b (A0) ; Write red,
Move.b (A4,D3),(A0) ; green,
Clr.b (A0) ; blue.
Dbra D0,@Repeat ; Loop until done.
Bra.s @EndLoop ; Go on.
@NotRadius Btst #IsMono,D5 ; If this is not a mono-only display
Beq.s @DoRGB ; then just do the standard RGB stuff.
Clr.b (A0) ; Otherwise, just write black out
Clr.b (A0) ; to the red & green channels.
Bra.s @DoMono ;
@DoRGB Move.b (A4,D3),(A0) ; Write red,
Move.b (A5,D3),(A0) ; green,
@DoMono Move.b (A6,D3),(A0) ; blue.
Dbra D0,@Repeat
@EndLoop MOVE (SP)+,SR ; restore the status reg
MOVE.B (SP)+,D0 ; get the MMU mode back
_SwapMMUMode ;
Movem.l (Sp)+,A4-A6/D5-D6 ; Restore work registers.
BSR DAFBSetDepth ; set the depth from D1
; Finish up the bookkeeping.
MOVE.W csMode(A2),saveMode(A3) ; save mode number
CMP.W #FifthVidMode,saveMode(A3) ; was it a direct mode?
BLT.S @BitOff ; no, so turn flag off
BSET #IsDirect,GFlags(A3) ; turn on bit
BRA.S @ModeOK1 ;
@BitOff
BCLR #IsDirect,GFlags(A3) ; turn off bit
@ModeOK1
Bsr DAFBCalcScreenBaseAddr ; Calculate the new ST-corrected screen baseAddr,
Move.l saveScreenBase(A3),csBaseAddr(A2) ; and return it.
BRA DAFBCtlGood ; return no error
ENDWITH
DAFBSetEntries
;---------------------------------------------------------------------
;
; 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 AuxDCE
; A2 = Ptr to cs parameter record
; A3 = Ptr to private data, later to CLUT constants table
; 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.
WITH DAFBVidPrivates
BTST #IsDirect,GFlags(A3) ; are we in a direct mode?
BNE DAFBCtlBad ; error if so
DAFBSEGuts
TST.L csTable(A2) ; Check for a nil pointer
BEQ DAFBCtlBad ;
MOVEM.L A1/A4-A6/D4-D7,-(SP) ; save registers for gamma
MOVE.W GFlags(A3),D5 ; get GFlags word in D5
CMP.W #indexEntries,csStart(A2) ; was it indexed mode?
BEQ.S @SkipSeq ; if so, then leave bit off (it's never turned on in GFlags)
BSET #UseSeq,D5 ; if not, turn on sequential mode bit
@SkipSeq
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,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
ADDQ #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
Btst #has16bppSRsrc,D5 ; If we have a 16bpp-capable sRsrc,
Bne.s @GetXTable ; then use the extended table.
Bra.s @NormTable ; Otherwise, just use the normal table.
@GetXTable Lea DAFBXClutTbl,A0 ; Point to extended table of counts.
Bra.s @ChkRange
@NormTable LEA DAFBClutTbl,A0 ; point to little table of counts
@ChkRange MOVEQ #0,D6 ; clear all of D6
MOVE.B (A0,D1),D6 ; get entry from table for this mode
;
; 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),D4 ; get the number of entries to change
CMP.W D6,D4 ; is it in the allowable range
BHI DAFBSEBadExit ; if out of range, then exit w/bad result
Move.w csStart(A2),D0 ; Get the start number to range check.
Addq.w #1,D0 ; If csStart < -1, then itÕs out of
Bmi DAFBSEBadExit ; range.
;
; In order to support Vesuvio & the RGB PortraitÕs 16bpp modes, we ALWAYS use indexed mode
; for SetEntries, since the real entries must be translated from a 5-bit value into an
; 8-bit index. Note: The UseTrans & UseSeq are actually the same bit so that the
; indexed write routine works correctly.
;
MOVE.L csTable(A2),D0 ; Some (bad) people pass in an offset
_StripAddress ; CTabHandleÕs MasterPointer here,
Move.l D0,A1 ; so we clean them up. Ugh!
Move.w D4,D1 ; Make a copy of the number of entries, and
Addq #1,D4 ; make it counting for now.
Moveq #0,D6 ; Assume that we arenÕt doing 16bpp translations.
; (i.e., #UseTrans in D6 is clear).
Btst #has16bppSRsrc,D5 ; If we have a 16bpp-capable sRsrc,
Bne.s @Chk16bpp ; then check for 16bpp.
Bra.s @IndexTest ; Otherwise, just do the normal stuff.
@Chk16bpp Move.w saveMode(A3),D0 ; Get the current mode.
Cmp.w #FifthVidMode,D0 ; If weÕre not doing 16bpp,
Bne.s @IndexTest ; then just go on.
Tst.b hasLin16bppCLUT(A3) ; If 16bpp is linear (i.e., we have an Antelope),
Bne.s @IndexTest ; then just on.
Bset #UseTrans,D6 ; Otherwise, remember that weÕre translating.
Bclr #UseSeq,D5 ; If weÕre already indexed,
Beq.s @isIndex ; then just go on.
Move.w D1,D2 ; Otherwise, sequence thru table from
Add.w csStart(A2),D2 ; csStart thru csCount entries.
; The following code is BAD, BAD, BAD! We should build our own table here so
; as to NOT mess up the userÕs data. But all the previous Apple video drivers
; have done the same thing here, so weÕll continue the trend for now.
@TableLoop Move.w D2,value(A1,D1*colorSpecSize) ; Write the index into the table.
Subq #1,D2 ; Decrement index.
Dbra D1,@TableLoop ;
Bra.s @isIndex
@IndexTest ADDQ #1,D4 ; make number of entries a counting number
BTST #UseSeq,D5 ; are we in sequential mode?
BEQ.S @isIndex ; if equal, we're indexed
@isSeq MULU #3,D4 ; room for R,G,B in sequential mode
BRA.S @allocIt ; and continue
@isIndex ASL #2,D4 ; multiply times 4 for index,R,G,B
@allocIt SUB.W D4,SP ; allocate the buffer and save size in D4
Btst #IsMono,D5 ; If this is not a mono-only display,
Beq.s @EndRdChk ; then just go on.
Moveq #true32b,D0 ; Set up to flip into 32-bit addressing mode.
_SwapMMUMode ; Do flip.
Move.b D0,-(Sp) ; Save previous addressing mode.
Move.l saveDAFBBase(A3),A0 ; Get the DAFBBase into A0.
Move.l DAFBFlags(A0),D0 ; Get the DAFBFlags into D0.
Btst #RadiusTPDBit,D0 ; If this is not a Radius TPD,
Beq.s @SwapBack ; then just go on.
Btst #RadiusDevType,D0 ; If this not a MonoTPD,
Bne.s @SwapBack ; then just go on.
Bset #IsMono,D6 ; Otherwise, remember to swap green & blue channels.
@SwapBack Move.b (Sp)+,D0 ; Set up to restore previous addressing mode.
_SwapMMUMode ; Do restore.
@EndRdChk
;
; Construct the stack version of the color table. It looks like a color table, but each of the
; components is only eight bits (rather than 16). These will be expanded to longs when they
; are written to the hardware
;
MOVE.L SP,A0 ; copy the stack buffer pointer
MOVE.W csCount(A2),D3 ; get the number of entries again
;
; Write the index if in indexed mode. If in sequential mode, blow it off completely,
; since it won't be needed.
@SetupLoop
MOVE.W (A1)+,D1 ; get index
BTST #UseSeq,D5 ; is it sequence mode?
BNE.S @SLSeq ; yup, so go there
Btst #UseTrans,D6 ; If weÕre not supposed to do the 5-to-8 translations,
Beq.s @WriteIndex ; then just write out the index to the stack.
Bsr DAFBTrans5to8 ; Otherwise, do the translation.
@WriteIndex MOVE.B D1,(A0)+ ; Write out index to 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
BTST #IsDirect,D5 ; test for direct mode as well
BNE.S @NoGray ; don't allow luminence mapping in direct mode
; 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},D0 ; get gChanWidth bits for gamma table lookup
MOVE.W D0,D1 ; copy into green register
MOVE.W D0,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,D6 ; If this is not a Radius MonoTPD,
Beq.s @NotRadius ; then just go on.
Clr.b (A0)+ ; Write black for red.
Move.b (A4,D0),(A0)+ ; Write gamma corrected ÒgreenÓ.
Clr.b (A0)+ ; Write black for blue.
Dbra D3,@SetupLoop ; Loop until done.
Bra.s @EndSetup ; Go on.
@NotRadius
BTST #IsMono,D5 ; if monochrome display, write black to red & green
BEQ.S @Brighter ; if not, then set all three channels
CLR.B (A0)+ ; write black for red
CLR.B (A0)+ ; and green
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
@EndSetup
;
; 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),A4 ; get VDAC base
LEA ACDC_DataReg(A4),A4 ; point to VDAC data register
MOVEQ #true32b,D0 ; flip to 32-bit addressing mode
_SwapMMUMode ;
MOVE.B D0,-(SP) ; save current addressing mode
LEA 2(SP),A0 ; point to the stack buffer again
CLR.L D1 ; get the high 3 bytes of D1 clear
MOVE.W SR,-(SP) ; preserve the status register
BSR DAFBWaitVSync ; wait for next blanking period (preserves A0/D0)
BTST #UseSeq,D5 ; is it sequence mode?
BNE.S DAFBSeqWrite ; yup, sequence mode, so go
;
; Here's the loop that actually writes to the hardware when in indexed mode.
;
DAFBIndexWrite
MOVE.B (A0)+,D1 ; get the index
MOVE.L D1,ACDC_AddrReg-ACDC_DataReg(A4) ; write the index value to the CLUT address
MOVE.B (A0)+,3(A4) ; write red
MOVE.B (A0)+,3(A4) ; write green
MOVE.B (A0)+,3(A4) ; write blue
Tst.b hasLin16BppCLUT(A3) ; If we donÕt have an Antelope part,
Beq.s @Next ; then just go on.
Tst.b ([VIA]) ; Otherwise, wait a µSec.
@Next DBRA D3,DAFBIndexWrite ; and loop
BRA.S DAFBSEDone ;
;
; Write the translated starting position for sequence mode.
;
DAFBSeqWrite
MOVE.W csStart(A2),D1 ; get sequence start address
MOVE.L D1,ACDC_AddrReg-ACDC_DataReg(A4) ; write the sequence start position
;
; Here's the loop that actually writes to the hardware when in sequence mode.
;
@SeqLoop
MOVE.B (A0)+,3(A4) ; write red
MOVE.B (A0)+,3(A4) ; write green
MOVE.B (A0)+,3(A4) ; write blue
Tst.b hasLin16BppCLUT(A3) ; If we donÕt have an Antelope part,
Beq.s @Next ; then just go on.
Tst.b ([VIA]) ; Otherwise, wait a µSec.
@Next DBRA D3,@SeqLoop ; and loop
;
; Clean up and go home.
;
DAFBSEDone
MOVE (SP)+,SR ; restore status register
MOVE.B (SP)+,D0 ; get the previous mode back
_SwapMMUMode ;
ADD D4,SP ; release stack buffer
MOVEM.L (SP)+,A1/A4-A6/D4-D7 ; restore registers
BRA DAFBCtlGood ; return O-Tay!
DAFBSEBadExit
MOVEM.L (SP)+,A1/A4-A6/D4-D7 ; restore registers
BRA DAFBCtlBad ; return an error code
ENDWITH
DAFBSetGamma
;---------------------------------------------------------------------
;
; 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 AuxDCE
; A2 = Ptr to cs parameter record
;
;---------------------------------------------------------------------
WITH DAFBVidPrivates
; 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 DAFBCtlBad ; => no, return error
Tst.w gType(A2) ; Test the hardwareID.
Beq.s @ChangeTable ; If 0, then accept a TFB-style gamma table.
CMP.W #drHwDAFB,gType(A2) ; type = DAFB?
BNE DAFBCtlBad ; => no, return error
TST.W gFormulaSize(A2) ; if gType=DAFB, 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 saveMonID(A3),D0 ; is this the monitor?
BEQ.S @ChangeTable ; yes, so do it
ADDQ #1,D0 ; was it -1?
BNE DAFBCtlBad ; nope, so must be wrong monitor
; If new table is a 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 Move.l saveGamDispPtr(A3),A0 ; if new one is smaller,
_DisposPtr ; dispose old one
CLR.L saveGamDispPtr(A3) ; flag it's been disposed
@GetNew Moveq #0,D0 ; (_NewPtr takes a long, so clear D0 for later.)
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 DAFBCtlBad ; => unable to allocate storage
MOVE.L saveGamDispPtr(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
Move.l A0,saveGamDispPtr(A3) ; save it for disposal
; 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.s @GammaDone ; Check to see if itÕs a direct device.
;
; 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 A0
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
Move.w gDataCnt(A0),D3 ; get the number of entries
Subq #1,D3 ; zero base
ADDA #gFormulaData,A0 ; point to tables
ADDA D0,A0 ; point past monID, if present
@ChanLoop MOVE.W D3,D0 ; loop count within each channel
@entryLoop MOVE.B D0,(A0) ; write this value out
Not.b (A0)+ ; invert to make table ramp properly
DBRA D0,@entryLoop ; for each entry in channel
DBRA D2,@ChanLoop ; and each channel
@GammaDone
BTST #IsDirect,GFlags(A3) ; are we in a direct mode?
BEQ.S @Out ; if not, then we're done
BSR DAFBDirectCLUTSet ; if so, then set up direct CLUT ramps
@Out
BRA DAFBCtlGood ; => return no error
ENDWITH
DAFBGrayPage
;---------------------------------------------------------------------
;
; Clear the specified page in the current mode to gray
;
; A0 = Ptr to private storage
; A1 = Ptr to AuxDCE
; A2 = Ptr to cs parameter record
; A3 = Ptr to driver privates
;
;---------------------------------------------------------------------
WITH DAFBVidPrivates
MOVE saveMode(A3),D1 ; D1 = mode
BSR DAFBChkMode ; convert mode to depth in D1
BNE DAFBCtlBad ; => not a valid depth
MOVE csPage(A2),D0 ; D0 = page
BNE DAFBCtlBad ; => not a valid page
BSR DAFBGrayScreen ; paint the screen gray
BTST #IsDirect,GFlags(A3) ; are we in a direct mode?
BEQ.S @Out ; if not, then we're done
BSR DAFBDirectCLUTSet ; if so, then set up direct CLUT ramps
@Out
BRA DAFBCtlGood ; => return no error
ENDWITH
DAFBSetGray
;---------------------------------------------------------------------
;
; 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 AuxDCE
; A2 = Ptr to cs parameter record
;
;---------------------------------------------------------------------
WITH DAFBVidPrivates
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 DAFBSetIntCom ; call common code
BRA DAFBCtlGood ; 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.
;
DAFBSetIntCom
MOVE.B csMode(A2),D0 ; get boolean
BFINS D0,GFlags(A3){D1:1} ; set flag bit
RTS ; and return
ENDWITH
DAFBSetInterrupt
;---------------------------------------------------------------------
;
; 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 AuxDCE
; A2 = Ptr to cs parameter record
; A3 = Ptr to private storage
;
;---------------------------------------------------------------------
WITH VDPageInfo,SlotIntQElement,DAFBVidPrivates
MOVEQ #1,D1 ; set up for BFEXTU to point to IntDisFlag
BSR.S DAFBSetIntCom ; call common code
BNE.S @DAFBDisableThem ; if zero, then enable
; This code enables interrupts and installs the interrupt handler.
;
BSR.S DAFBEnableVGuts ; call common code
BNE DAFBCtlBad ; error, flag problem
BRA DAFBCtlGood ; and go home
; This code disables VBL interrupts, then removes the interrupt handler.
;
@DAFBDisableThem
BSR.S DAFBDisableVGuts ; jump to the disabling utility
BRA DAFBCtlGood ; all done
; The following two routines are common code shared between the Open/Close calls
; and the SetInterrupt control call.
;
DAFBDisableVGuts
MOVEQ #true32b,D0 ; flip to 32-bit addressing mode
_SwapMMUMode ;
MOVE.B D0,-(SP) ; save current addressing mode
MOVE.W SR,-(SP) ; preserve the status register
BSR DAFBWaitVSync ; to be safe, wait for the next VBL
MOVE.L saveDAFBBase(A3),A0 ; point to the DAFB base
CLR.L Swatch_IntMsk(A0) ; set slot 0 interrupt disabled
MOVE (SP)+,SR ; re-enable cursor interrupts
MOVE.B (SP)+,D0 ; get back addressing mode
_SwapMMUMode ;
CLR D0 ; setup slot # for _SIntRemove (slot zero!)
MOVE.L saveSQElPtr(A3),A0 ; get the SQ element pointer
_SIntRemove ; remove the interrupt handler
RTS
DAFBEnableVGuts ;
MOVE.L saveSQElPtr(A3),A0 ; get the queue element
LEA DAFBBeginIH,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 A3,SQParm(A0) ; pass pointer to privates as the parameter
CLR.W D0 ; setup slot zero
_SIntInstall ; and do install
BNE.S @IntBad
MOVEQ #true32b,D0 ; flip to 32-bit addressing mode
_SwapMMUMode ;
MOVE.B D0,-(SP) ; save current addressing mode
MOVE.L saveDAFBBase(A3),A0 ; point to the DAFB base
; DAFBÕs vertical timing generator is driven from a clock which is only half the frequency of the horizontal
; timing generator clock. Therefore, all the vertical timing registers are double-sized. However, the
; CrsrLine register is specified in whole lines. So, in order to get VBL happening at just the right
; time, we must divide VFP by 2.
;
Move.l Swatch_VFP(A0),D0 ; Get current VFP.
Andi.l #$FFF,D0 ; Strip off junk.
Lsr.l #1,D0 ; Divide by 2.
Addq #1,D0 ; Add 1.
Move.l D0,Swatch_CrsrLine(A0) ; Set interrupt to occur AFTER VFP, and
Move.l #dafbEnableVInts,Swatch_IntMsk(A0) ; turn on interrupt.
MOVE.B (SP)+,D0 ; get addressing mode back
_SwapMMUMode ;
CMP D0,D0 ; clear z-bit for good result
@IntBad RTS ; return home (if bad, z-bit is set above, so just leave) <8>
ENDWITH
DAFBDirectSetEntries
;---------------------------------------------------------------------
;
; Change the CLUT in a direct mode.
;
; A1 = Ptr to AuxDCE
; A2 = Ptr to cs parameter record
; A3 = Ptr to private storage
;
; This routine allows knowledgeable programs modify the contents
; of the CLUT in direct modes (usually for limited color previewing).
; It takes the same parameter block as SetEntries, but SetEntries
; intentionally does not operate when the card is in a direct pixMode.
; This routine takes the same data and operates ONLY when in direct
; modes. It calls the same SetEntries guts as the regular routine.
;
;---------------------------------------------------------------------
BTST #IsDirect,GFlags(A3) ; are we in a direct mode?
BEQ DAFBCtlBad ; error if not
BRA DAFBSEGuts ; jump to SetEntries internals if it's OK
DAFBSetDefaultMode
;---------------------------------------------------------------------
;
; Write the card default mode into slot pRAM.
;
; A1 = Ptr to AuxDCE
; 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,DAFBVidPrivates,SP_Params
;
; 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. Built-in video keeps the video
; sRsrc spID in VendorUse2.
;
SUBA #SizesPRAMRec,SP ; allocate block for pRAM record
MOVE.L SP,spResult(A0) ; point to it
_sReadPRAMRec ; read it
;
; Since PrimaryInit relies on the default mode being set correctly, we check to see that
; the mode to be set is actually valid. Monitors can only see valid sRsrcIDs, so
; it probably wonÕt cause a problem. But we should check it anyway for unsavory
; applications.
;
Move.b csMode(A2),spID(A0) ; Look for the passed in spID.
Clr.l spParamData(A0) ; Clear the fNext flag; we want THIS sRsrc.
Ori.b #(1<<fall)|\ ; Search for both enabled/disabled sRsrcÕs
(1<<foneslot),spParamData+3(A0) ; Only search in our slot.
_GetsRsrc ; Do it.
Bne.s @BadExit ; If failed, quit.
Move.w spCategory(A0),D0 ; Get the category.
Cmp.w #catDisplay,D0 ; If itÕs not catDisplay,
Bne.s @BadExit ; then quit.
Move.w spCType(A0),D0 ; Get the type.
Cmp.w #typVideo,D0 ; If itÕs not typVideo,
Bne.s @BadExit ; then quit.
Move.w spDrvrSw(A0),D0 ; Get the software kind.
Cmp.w #drSwApple,D0 ; If itÕs not drSwApple,
Bne.s @BadExit ; then quit.
Move.w spDrvrHw(A0),D0 ; Get the hardware ID.
Cmp.w #drHwDAFB,D0 ; If itÕs not drHwDAFB,
Bne.s @BadExit ; then quit.
;
; 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.
;
Btst #IsDirect,GFlags(A3) ; If weÕre not in a direct mode,
Beq.s @WriteIt ; just go on.
Move.b csMode(A2),D0 ; Get the mode weÕre going to.
Cmp.b #sRsrc_Vid_DAFB_NTSCconvSTx,D0 ; If weÕre not going to a convolved mode,
Blt.s @WriteIt ; just go on.
Cmp.b #sRsrc_Vid_DAFB_PALconvFF,D0 ;
Bgt.s @WriteIt ;
Move.b #FourthVidMode,SP_Depth(Sp) ; Otherwise, reset the depth to indexed.
@WriteIt MOVE.B csMode(A2),SP_LastConfig(SP) ; write the mode into pRAM buffer
MOVE.L SP,spsPointer(A0) ; set up parameter block
_sPutPRAMRec ; write the new record out
@GoodExit ADDA #SizesPRAMRec+spBlockSize,SP ; Deallocate buffer and
BRA DAFBCtlGood ; return good result.
@BadExit Adda #SizesPRAMRec+spBlockSize,SP ; Deallocate buffer and
Bra DAFBCtlBad ; return bad result.
ENDWITH
DAFBSetSyncOnGreen
;---------------------------------------------------------------------
;
; Enable (csMode = 0) or disable (csMode = non-zero) the sync on green.
;
; A1 = Ptr to AuxDCE
; A2 = Ptr to cs parameter record
; A3 = Ptr to private storage
;
;---------------------------------------------------------------------
With spBlock,DAFBVidPrivates,SP_Params
;
; First, set up a slot parameter block on the stack.
;
Suba #spBlockSize,Sp ; Make a SpBlock on the stack.
Move.l Sp,A0 ; Get a pointer to it into A0.
Move.b dCtlSlot(A1),spSlot(A0) ; Set it up.
Clr.b spExtDev(A0)
;
; Next, read the current pRam record so that we can write it back if necessary.
;
Suba #SizesPRAMRec,Sp ; Make an sPRAM block on the stack.
Move.l Sp,spResult(A0) ; Point to it.
_sReadPRamRec ; Get pRAM.
;
; See what we need to doÉ
;
Tst.b csMode(A2) ; If csMode = 0, then we are
Beq.s @EnableSyncOnGreen ; enabling sync on green.
Btst #syncOnGreen,GFlags(A3) ; If weÕre already NOT putting sync on green,
Beq.s @Done ; then thereÕs nothing left to do.
Bclr #syncOnGreen,GFlags(A3) ; Otherwise, set up the GFlags field,
Bclr #spSyncOnGreen,SP_Flags(Sp) ; the pRam record, and
Moveq #0,D1 ; the toggle bit.
Bra.s @SyncCommon ;
@EnableSyncOnGreen
Btst #syncOnGreen,GFlags(A3) ; If weÕre already putting sync on green,
Bne.s @Done ; then thereÕs nothing left to do.
Bset #syncOnGreen,GFlags(A3) ; Otherwise, set up the GFlags field
Bset #spSyncOnGreen,SP_Flags(Sp) ; the pRam record, and
Moveq #1,D1 ; the toggle bit.
@SyncCommon
Move.l Sp,spsPointer(A0) ; Set up to whack pRam.
_sPutPRAMRec ; Whack it.
Moveq #true32b,D0 ; Set up to flip into 32-bit addressing mode.
_SwapMMUMode ; Do flip.
Move.b D0,-(Sp) ; Save previous mode for later.
Move.w Sr,-(Sp) ; Save the current interrupt level.
Bsr DAFBWaitVSync ; Wait for VBL at level 2.
Move.w (Sp)+,Sr ; Restore interrupt level.
Tst.b wombatFlag(A3) ; If weÕre not on a Wombat,
Beq.s @VIASOG ; then use the VIA SOG.
Move.l saveDAFBBase(A3),A0 ; Get DAFBBase into A0.
Move.l DAFB_ClkCfg(A0),D0 ; Get the current clock config value.
Bfins D1,D0{dafbSyncOnGreen:1} ; Toggle the sync-on-green bit appropriately,
Move.l D0,DAFB_ClkCfg(A0) ; apply it.
Bra.s @EndSOG ;
@VIASOG Move.l VIA2,A0 ; Point to VIA2.
Btst #0,D1 ; If weÕre supposed to put sync on green,
Bne.s @SyncOnGreen ; then hop to it.
Bclr #v2SyncOnGreen,vBufA(A0) ; Otherwise, disable sync on green.
Bra.s @EndSOG
@SyncOnGreen
Bset #v2SyncOnGreen,vBufA(A0) ; Enable sync on green.
@EndSOG Move.b (Sp)+,D0 ; Set up to switch back to prev mode,
_SwapMMUMode ; and do it.
@Done Adda #SizesPRAMRec+spBlockSize,Sp ; Restore stack, and
Bra DAFBCtlGood ; go home.
EndWith
DAFBSet16bpp
;---------------------------------------------------------------------
;
; Enable (csMode = 0) or disable (csMode = non-zero) the 16bpp mode
; if AC842A is around.
;
; Notes: To determine if 16bpp is possible, one should call
; Get16bpp. If it returns noErr, then 16bpp is
; possible, otherwise it isnÕt.
;
; To determine if 16bpp is ALWAYS non-blocked, one should
; attempt to disable 16bpp mode. If noErr is returned,
; but Get16bpp returns the enabled state, then the
; 16bpp is always non-blocked.
;
; A1 = Ptr to AuxDCE
; A2 = Ptr to cs parameter record
; A3 = Ptr to private storage/ptr to DAFBBase addr (not restored)
;
;---------------------------------------------------------------------
With spBlock,DAFBVidPrivates,SP_Params
;
; First, set up a slot parameter block on the stack.
;
Suba #spBlockSize,Sp ; Make an SpBlock on the stack.
Move.l Sp,A0 ; Get a pointer to it into A0.
Move.b dCtlSlot(A1),spSlot(A0) ; Set it up.
Clr.b spExtDev(A0)
;
; Next, read the current pRam so that we can tell whether an AC842A is actually
; intalled.
;
Suba #SizesPRAMRec,Sp ; Make an sPRAM block on the stack.
Move.l Sp,spResult(A0) ; Point to it.
_sReadPRamRec ; Get pRAM.
Btst #spHas16bppACDC,SP_Flags(Sp) ; If we donÕt have an AC842A,
Beq.s @BadExit ; then just blow this off.
Moveq #true32b,D0 ; Set up to switch into 32-bit mode,
_SwapMMUMode ; do switch, and
Move.b D0,D1 ; save previous mode.
Btst #IsSlow,GFlags(A3) ; If CPU is running at 25MHz,
Bne.s @DoSet ; then do things as normal.
Move.l saveDAFBBase(A3),A3 ; Get DAFBBase into A3.
Move.l DAFB_Test(A3),D0 ; Get the DAFBTest register.
Andi.w #$0FFF,D0 ; Strip off the junk.
Moveq #9,D2 ; Get the amount to shift.
Lsr.w D2,D0 ; Shift in the version number.
Cmp.b #DAFB3Vers,D0 ; If we donÕt have a DAFB 3,
Blt.s @DoSet ; then do things as normal.
Bra.s @GoodExit ; Otherwise, 16bpp is always set.
;
; See what we need to doÉ
;
@DoSet Tst.b csMode(A2) ; If csMode = 0, then we are
Beq.s @Allow16bpp ; allowing 16bpp.
Bclr #spAllow16bpp,SP_Flags(Sp) ; If we are already blocking 16bpp
Beq.s @GoodExit ; then no need to whack pRam again.
Bra.s @16BppCommon ; Otherwise, whack it.
@Allow16bpp Bset #spAllow16bpp,SP_Flags(Sp) ; If we are already allowing 16bpp,
Bne.s @GoodExit ; then no need to whack pRam again.
@16bppCommon Move.l Sp,spsPointer(A0) ; Set up to whack pRam.
_sPutPRAMRec ; Whack it.
@GoodExit Move.b D1,D0 ; Set up to switch back into previous mode,
_SwapMMUMode ; do switch, and
Adda #SizesPRAMRec+spBlockSize,Sp ; Restore stack, and
Bra DAFBCtlGood ; go home.
@BadExit Adda #SizesPRAMRec+spBlockSize,Sp ; Restore stack, and
Bra DAFBCtlBad ; return error.
EndWith
DAFBSetPageMode
;---------------------------------------------------------------------
;
; Enable (csMode = 0) or disable (csMode = non-zero) Page Mode.
;
; A1 = Ptr to AuxDCE/ptr to DAFBBase addr (not restored)
; A2 = Ptr to cs parameter record
; A3 = Ptr to private storage
;
;---------------------------------------------------------------------
With spBlock,DAFBVidPrivates,SP_Params
;
; First, set up a slot parameter block on the stack.
;
Suba #spBlockSize,Sp ; Make an SpBlock on the stack.
Move.l Sp,A0 ; Get a pointer to it into A0.
Move.b dCtlSlot(A1),spSlot(A0) ; Set it up.
Clr.b spExtDev(A0)
;
; Next, read the current pRam so that we can set it appropriatelyÉ
;
Suba #SizesPRAMRec,Sp ; Make an sPRAM block on the stack.
Move.l Sp,spResult(A0) ; Point to it.
_sReadPRamRec ; Get pRAM.
Moveq #true32b,D0 ; Set up to switch into 32-bit mode,
_SwapMMUMode ; do switch, and
Move.b D0,D1 ; save previous mode.
Move.l saveDAFBBase(A3),A1 ; Get DAFBBase into A1 for below.
;
; See what we need to doÉ
;
Tst.b csMode(A2) ; If csMode = 0, then we are
Beq.s @EnablePageMode ; enabling page mode.
Move.b #0,pageModeSet(A3) ; Say page mode is disaabled.
Bclr #spPageMode,SP_Flags(Sp) ; Flip pRam bit.
Bra.s @EndPageMode ;
@EnablePageMode Move.b #1,pageModeSet(A3) ; Say page mode is enabled.
Bset #spPageMode,SP_Flags(Sp) ; Flip pRam bit.
@EndPageMode Move.l Sp,spsPointer(A0) ; Set up to whack pRam.
_sPutPRAMRec ; Whack it.
Adda #SizesPRAMRec+spBlockSize,Sp ; Restore stack.
Move.l DAFB_Config(A1),D0 ; Read the DAFBConfig register.
Bfextu D0{dafbWrdIntBit:1},D0 ; If word-interleave is on
Bne.s @DisablePageMode ; then ALWAYS disable page mode.
Tst.b pageModeSet(A3) ; If weÕre not supposed to enable page mode,
Beq.s @DisablePageMode ; then disable it.
Moveq #1,D0 ; Otherwise, set up to enable page mode,
Bra.s @HitPageMode ; and do it.
@DisablePageMode
Moveq #0,D0 ; Set up to disable page mode, and
@HitPageMode Move.l D0,DAFB_PgMdEn(A1) ; and do it.
@ExitPageMode Move.b D1,D0 ; Set up to switch back into previous mode,
_SwapMMUMode ; do switch, and
Bra DAFBCtlGood ; leave.
EndWith
DAFBSetAltSense
;---------------------------------------------------------------------
;
; SetAltSense sets up the alternate senseID pRam byte to contain
; a valid ÒindexÓ code if a valid sense code is passed
; in csMode (byte 0 is the sense code, byte 1 is the type).
;
; A1 = Ptr to AuxDCE/Ptr to DAFBMonIDs table (not restored)
; A2 = Ptr to cs parameter record
; A3 = Ptr to private storage
;
;---------------------------------------------------------------------
With spBlock,DAFBVidPrivates,SP_Params
;
; First, set up a slot parameter block on the stack.
;
Suba #spBlockSize,Sp ; Make an SpBlock on the stack.
Move.l Sp,A0 ; Get a pointer to it into A0.
Move.b dCtlSlot(A1),spSlot(A0) ; Set it up.
Clr.b spExtDev(A0)
;
; Next, read the current pRam so that we can set it appropriatelyÉ
;
Suba #SizesPRAMRec,Sp ; Make an sPRAM block on the stack.
Move.l Sp,spResult(A0) ; Point to it.
_sReadPRamRec ; Get pRAM.
;
; See what we need to doÉ
;
Move.b csMode+1(A2),D0 ; Get the sense-code type.
Beq.s @NoConnect ; If indexed (0), use type 7.
Cmp.b #indexedSense2P,D0 ; If we got a type 3,
Beq.s @2PExtended ; then go there.
Cmp.b #indexedSenseHR,D0 ; If we got a type 6,
Beq.s @HRExtended ; then go there.
Cmp.b #indexedNoConnect,D0 ; If we got a type 7,
Beq.s @NoConnect ; then go there.
Bra @MonIDNotValid ; Otherwise, return an error.
@2PExtended
Move.b csMode(A2),D1 ; Get the sense code into D0.
Cmp.b #extended2PRdRGB,D1 ; If itÕs the Radius ColorTPD,
Beq @WriteIt ; then write it out.
Cmp.b #extended2PRdMono,D1 ; If itÕs the Radius MonoTPD,
Beq.s @WriteIt ; then write it out.
Bra @MonIDNotValid ; Otherwise, return an error.
@HRExtended
Cmp.b #extendedHR,csMode(A2) ; If itÕs not the MultiSync code,
Bne @MonIDNotValid ; return an error.
Move.b #indexedSenseHR,D1 ; Otherwise, default to HR.
Bra.s @WriteIt
@NoConnect
Move.b csMode(A2),D1 ; Get the monID.
Cmp.b #indexedNoConnect,D1 ; If itÕs one of the no-connect codes,
Beq.s @ClearIt ; then zero-out the no-connect pRam byte.
Cmp.b #extendedNoConnect,D1 ;
Beq.s @ClearIt ;
Lea DAFBMonIDs,A1 ; Get ptr to DAFBMonIDs table.
Move.w (A1)+,D0 ; Get count of modes.
@ValidLoop Move.b (A1)+,D1 ; Get an ID from the table.
Cmp.b csMode(A2),D1 ; If we have a match,
Beq.s @FoundMatch ; say so.
Dbra D0,@ValidLoop ; Otherwise, keep looping thru
Bra.s @MonIDNotValid ; table until no match is found.
@FoundMatch Tst.b csMode+1(A2) ; If this is not an extended code,
Beq.s @WriteIt ; then just do write.
Cmp.b #extendedSenseVGA,D1 ; Is it the VGA code?
Bne.s @TryPal ; Nope, try PAL.
Move.b #indexedSenseVGA,D1
Bra.s @WriteIt
@TryPal Cmp.b #extendedSensePAL,D1 ; Is it the PAL code?
Bne.s @TryPALBox ; Nope, try PAL encoder box.
Move.b #indexedSensePAL,D1
Bra.s @WriteIt
@TryPALBox Cmp.b #extendedSensePALBox,D1 ; Is it the PAL encoder box code?
Bne.s @TryNTSC ; Nope, try NTSC encoder box.
Move.b #indexedSensePAL,D1
Bra.s @WriteIt
@TryNTSC Cmp.b #extendedSenseNTSC,D1 ; Is it the NTSC encoder box code?
Bne.s @TryLP ; Nope, try GoldFish.
Move.b #indexedSenseNTSC,D1
Bra.s @WriteIt
@TryLP Cmp.b #extendedSenseLP,D1 ; Is it the GoldFish?
Bne.s @Try19 ; Nope, try 19Ó.
Move.b #indexedSenseLP,D1 ;
Bra.s @WriteIt
@Try19 Cmp.b #extendedSense19,D1 ; Is it a 19Ó?
Bne.s @WriteIt ; Nope, must be indexed.
Move.b #indexedSense19,D1
@WriteIt Move.b D1,SP_AltSense(Sp) ; Write out ÒindexÓ to pRam record.
Ori.b #spAltSenseValidMask,SP_AltSense(Sp) ; Validate it.
Bra.s @WritePRam
@ClearIt Clr.b SP_AltSense(Sp) ; Invalidate no-connect byte.
@WritePRam Move.l Sp,spsPointer(A0) ; Set up to whack pRam.
_sPutPRAMRec ; Whack it.
Adda #SizesPRAMRec+spBlockSize,Sp ; Restore stack.
Bra DAFBCtlGood ; leave.
@MonIDNotValid Adda #SizesPRAMRec+spBlockSize,Sp ; Restore stack.
Bra DAFBCtlBad ; leave with error.
Endwith
**********************************************************************
*
* VideoClose releases the device's private storage and removes the
* interrupt handler.
*
*
* Entry: A0 = param block pointer
* A1 = AuxDCE pointer
*
* Other: A2 = temporary AuxDCE pointer copy
*
**********************************************************************
DAFBVidClose
WITH DAFBVidPrivates
MOVE.L dCtlStorage(A1),A3 ; A3 <- Ptr to private storage
MOVE.L (A3),D0 ;
_StripAddress ;
MOVE.L D0,A3 ;
BSR DAFBDisableVGuts ; call utility to deactivate interrupts
Moveq #true32b,D0 ; Set up to flip into 32-bit addressing.
_SwapMMUMode ; Flip.
Move.l saveDAFBBase(A3),A2 ; (Get DAFBBase into A2 for DAFBIdle macro.)
DAFBIdle ; Put DAFB into an idle state.
_SwapMMUMode ; Restore previous addressing mode.
MOVE.L saveSQElPtr(A3),A0 ; get the slot interrupt queue element ptr
_DisposPtr
MOVE.L saveGamDispPtr(A3),A0 ; get pointer to gamma table block
_DisposPtr ; and dispose it
Move.l saveVidPtr(A3),A0 ; Get pointer to video parameters block,
_DisposPtr ; and dispose of it.
MOVE.L dCtlStorage(A1),A0 ; dispose of the private storage
_DisposHandle ;
MOVEQ #noErr,D0 ; no error
RTS ; and return
ENDWITH
**********************************************************************
*
* Video Driver Status Call Handler. There are ten standard calls:
*
* ($00) Error
* ($01) Error
* ($02) GetMode
* ($03) GetEntries
* ($04) GetPage
* ($05) GetPageBase
* ($06) GetGray
* ($07) GetInterrupt
* ($08) GetGamma
* ($09) GetDefaultMode
*
* The following calls are DAFB-specific:
*
* ($80) GetSyncOnGreen
* ($81) Get16bpp
* ($82) GetPageMode
* ($83) GetAltSense
*
* Entry: A0 = paramblock pointer
* A1 = AuxDCE pointer
* Uses: A2 = cs parameters
* A3 = pointer to private storage
* D0-D3 = scratch (don't need to be preserved)
*
* Exit: D0 = error code
*
**********************************************************************
DAFBVidStatus
MOVEM.L A0/A1,-(SP) ; Save exit registers.
MOVE.L csParam(A0),A2 ; A2 <- Ptr to control parameters
MOVE.L dCtlStorage(A1),A3 ; A3 <- Ptr to private storage
MOVE.L (A3),D0 ;
_StripAddress ;
MOVE.L D0,A3 ;
MOVE.W csCode(A0),D0 ; get routine selector
Cmp.w #cscSyncOnGreen,D0 ; If we got the GetSyncOnGreen call,
Beq DAFBGetSyncOnGreen ; hop to it.
Cmp.w #csc16bpp,D0 ; If we got the Get16bpp call,
Beq DAFBGet16bpp ; hop to it.
Cmp.w #cscPageMode,D0 ; If we got the PageMode call,
Beq DAFBGetPageMode ; hop to it.
Cmp.w #cscAltSense,D0 ; If we got the AltSense call,
Beq DAFBGetAltSense ; hop to it.
CMP.W #9,D0 ;IF csCode NOT IN [0..9] THEN
BHI.S DAFBStatBad ; Error, csCode out of bounds.
MOVE.W DAFBStatJumpTbl(PC,D0.W*2),D0 ;Get the relative offset to the routine.
JMP DAFBStatJumpTbl(PC,D0.W) ;GOTO the proper routine.
DAFBStatJumpTbl
DC.W DAFBStatBad-DAFBStatJumpTbl ;$00 => Error
DC.W DAFBStatBad-DAFBStatJumpTbl ;$01 => Error
DC.W DAFBGetMode-DAFBStatJumpTbl ;$02 => GetMode
DC.W DAFBGetEntries-DAFBStatJumpTbl ;$03 => GetEntries
DC.W DAFBGetPage-DAFBStatJumpTbl ;$04 => GetPage
DC.W DAFBGetPageBase-DAFBStatJumpTbl ;$05 => GetPageBase
DC.W DAFBGetGray-DAFBStatJumpTbl ;$06 => GetGray
DC.W DAFBGetInterrupt-DAFBStatJumpTbl ;$07 => GetInterrupt
DC.W DAFBGetGamma-DAFBStatJumpTbl ;$08 => GetGamma
DC.W DAFBGetDefaultMode-DAFBStatJumpTbl ;$09 => GetDefaultMode
DAFBStatBad MOVEQ #statusErr,D0 ; else say we don't do this one
BRA.S DAFBStatDone ; and return
DAFBStatGood MOVEQ #noErr,D0 ; return no error
DAFBStatDone MOVEM.L (SP)+,A0/A1 ; Restore exit registers.
BRA DAFBExitDrvr
DAFBGetMode
;---------------------------------------------------------------------
;
; Return the current mode
;
; Inputs : A2 = pointer to csParams
; A3 = pointer to private storage
;
;---------------------------------------------------------------------
WITH DAFBVidPrivates
MOVE.W saveMode(A3),csMode(A2) ; return the mode
Clr.w csPage(A2) ; return the page number (always 0)
Move.l saveScreenBase(A3),csBaseAddr(A2) ; Return the ST-corrected screen baseAddr.
BRA.S DAFBStatGood ; => return no error
ENDWITH
DAFBGetEntries
;---------------------------------------------------------------------
;
; Read the current contents of the CLUT. These values were gamma corrected
; when they were set (by DAFBSetEntries), so they may not match the source
; cSpec array.
;
; Inputs : A1 = pointer to AuxDCE
; A2 = pointer to csParams/CLUT read register (not restored to csParams)
; A3 = pointer to private storage
;
;---------------------------------------------------------------------
Movem.l D4-D6,-(Sp) ; Save work registers.
Tst.l -(Sp) ; Make some room.
Move.l csTable(A2),D0 ; If we were handed a nil pointer,
Beq @GEErr ; then hike.
_StripAddress ; Make table pointer 32-bit clean.
Move.l D0,(Sp) ; And save it.
Move.w saveMode(A3),D1 ; Get the current video mode.
Sub.w #firstVidMode,D1 ; Convert it to an index.
Move.l D1,D6 ; Save it for later.
Move.w GFlags(A3),D5 ; Get the flags for quick access.
Btst #has16bppSRsrc,D5 ; If we have a 16bpp-capable sRsrc,
Bne.s @GetXTable ; then use the extended table.
Lea DAFBClutTbl,A0 ; Otherwise, just use the normal table.
Bra.s @ChkRange ;
@GetXTable Lea DAFBXClutTbl,A0 ; Point to extended table of counts.
Cmp.w #FifthVidMode-FirstVidMode,D6 ; If this is not 16bpp mode,
Bne.s @ChkRange ; then just go on.
Tst.b hasLin16bppCLUT(A3) ; If 16bpp is linear (i.e., we have Antelope),
Bne.s @ChkRange ; then just on.
Bset #UseTrans,D5 ; Otherwise, remember to do translation.
@ChkRange Moveq #0,D3 ; Set up to get count.
Move.b (A0,D1.w),D3 ; Get clut count.
Move.w csCount(A2),D4 ; Get the number of entries to fill,
Bmi.s @GEErr ; and hike if itÕs out of range.
Cmp.w D3,D4 ; If D4-D3 > 0 (count > entries),
Bhi.s @GEErr ; then hike.
Move.w D4,D2 ; Otherwise, copy the count.
Cmp.w #indexEntries,csStart(A2) ; If table accesses are to be indexed,
Beq.s @GECom ; then go on.
Move.w D4,D1 ; Otherwise, sequence thru table from
Add.w csStart(A2),D2 ; csStart thru csCount entries.
; The following code is BAD, BAD, BAD! We should build our own table here so
; as to NOT mess up the userÕs data. But all the previous Apple video drivers
; have done the same thing here, so weÕll continue the trend for now.
Move.l (Sp),A0 ; Get ptr to csTable.
@TableLoop Move.w D2,value(A0,D1*colorSpecSize) ; Write the index into the table.
Subq #1,D2 ; Decrement index.
Dbra D1,@TableLoop ;
@GECom Moveq #true32b,D0 ; Save previous MMU mode and set MMU to
_SwapMMUMode ; 32-bit addressing when dealing with DAFB.
Move.l (Sp)+,A0 ; Get/restore ptr to csTable.
Move.l saveVDACBase(A3),A2 ; Get ACDC base address.
Add.l #ACDC_DataReg,A2 ; Add offset to Clut read register.
Move.w Sr,-(Sp) ; Save current interrupt level
Bsr DAFBWaitVSync ; Wait for VBL.
@Repeat Move.w value(A0),D1 ; Get the NEXT Clut position into D1.
Cmp.w D3,D1 ; If this position is out of range,
Bhi.s @Until ; then go on.
Btst #UseTrans,D5 ; If weÕre not supposed to translate this index,
Beq.s @Index ; then just go on.
Bsr DAFBTrans5to8 ; Otherwise, do translation.
@Index Move.l D1,ACDC_AddrReg-ACDC_DataReg(A2) ; Tell the Clut where to read from.
Nop ; (DAFB address space is non-serial.)
Move.l (A2),D1 ; Get Red:
Move.b D1,rgb+red(A0) ; --> $rrXX
Move.b D1,rgb+red+1(A0) ; --> $rrrr
Move.l (A2),D1 ; Get Green:
Move.b D1,rgb+green(A0) ; --> $ggXX
Move.b D1,rgb+green+1(A0) ; --> $gggg
Move.l (A2),D1 ; Get Blue:
Move.b D1,rgb+blue(A0) ; --> $bbXX
Move.b D1,rgb+blue+1(A0) ; --> $bbbb
@Until Addq #colorSpecSize,A0 ; Point to next entry ColorTable.
Dbra D4,@Repeat
Move.w (Sp)+,Sr ; Restore previous interrupt level.
_SwapMMUMode ; Restore previous addressing mode.
Movem.l (Sp)+,D4-D6 ; Restore work registers.
Bra DAFBStatGood ; Return noError.
@GEErr Tst.l (Sp)+ ; Clean up stack.
Movem.l (Sp)+,D4-D6 ; Restore work registers.
Bra DAFBStatBad ; Return statError.
DAFBGetPage
;---------------------------------------------------------------------
;
; Return the number of pages in the specified mode. It's pretty simple;
; every mode has only one page. We do check if it's valid, however.
;
;---------------------------------------------------------------------
WITH DAFBVidPrivates
MOVE csMode(A2),D1 ; get the mode
MOVE D1,D2 ; keep a copy
BSR DAFBChkMode ; is this mode OK?
BNE DAFBStatBad ; => not a valid mode
MOVE.W #1,csPage(A2) ; return page count
BRA DAFBStatGood ; => return no error
ENDWITH
DAFBGetPageBase
;---------------------------------------------------------------------
;
; Return the base address for the specified page in the current mode
;
;---------------------------------------------------------------------
WITH DAFBVidPrivates
TST.W csPage(A2) ; are we returning page zero info?
BNE DAFBStatBad ; only page 0 is valid
Move.l saveScreenBase(A3),csBaseAddr(A2) ; Return the ST-corrected screen baseAddr.
BRA DAFBStatGood ; => return no error
ENDWITH
DAFBGetGray
;---------------------------------------------------------------------
;
; Return a boolean, set true if luminance mapping is on
;
;---------------------------------------------------------------------
WITH DAFBVidPrivates
MOVEQ #0,D1 ; set up for BFEXTU
DAFBGetFlagCom
BFEXTU GFlags(A3){D1:1},D0 ; get the state of flag
MOVE.B D0,csMode(A2) ; return value
BRA DAFBStatGood ; => and return
ENDWITH
DAFBGetInterrupt
;---------------------------------------------------------------------
;
; Return a boolean in csMode, set true if VBL interrupts are disabled
;
;---------------------------------------------------------------------
WITH DAFBVidPrivates
MOVEQ #1,D1 ; set up BFEXTU to point at IntDisFlag
BRA.S DAFBGetFlagCom ; and use common code
ENDWITH
DAFBGetGamma
;---------------------------------------------------------------------
;
; Return the pointer to the current gamma table
;
;---------------------------------------------------------------------
WITH DAFBVidPrivates
MOVE.L saveGammaPtr(A3),csGTable(A2) ; return the pointer to the structure
BRA DAFBStatGood ; and return a good result
ENDWITH
DAFBGetDefaultMode
;---------------------------------------------------------------------
;
; Read the card default mode from slot pRAM.
;
; A1 = Ptr to AuxDCE
; A2 = Ptr to cs parameter record
; A3 = Ptr to private storage
;
;---------------------------------------------------------------------
WITH spBlock,DAFBVidPrivates,SP_Params
;
; 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. Built-in video 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 SP_LastConfig(SP),csMode(A2) ; return the result
ADDA #SizesPRAMRec+spBlockSize,SP ; release buffer
BRA DAFBStatGood ;
ENDWITH
DAFBGetSyncOnGreen
;---------------------------------------------------------------------
;
; Return a boolean in csMode, set true if sync-on-green is disabled.
;
;---------------------------------------------------------------------
With DAFBVidPrivates
Btst #syncOnGreen,GFlags(A3) ; If weÕre putting sync on green,
Bne.s @IsOn ; then return enabled state.
Move.b #1,csMode(A2) ; Otherwise, return disabled.
Bra DAFBStatGood
@IsOn
Clr.b csMode(A2) ; Return enabled state.
Bra DAFBStatGood
EndWith
DAFBGet16bpp
;---------------------------------------------------------------------
;
; Return a boolean in csMode, set true if 16bpp is blocked.
;
;---------------------------------------------------------------------
With spBlock,DAFBVidPrivates,SP_Params
;
; First, set up a slot parameter block on the stack.
;
Suba #spBlockSize,Sp ; Make a SpBlock on the stack.
Move.l Sp,A0 ; Get a pointer to it into A0.
Move.b dCtlSlot(A1),spSlot(A0) ; Set it up.
Clr.b spExtDev(A0)
;
; Next, read the current pRam so that we can tell whether an AC842A is actually
; intalled, and then return whether 16bpp is blocked or not.
;
Suba #SizesPRAMRec,Sp ; Make an sPRAM block on the stack.
Move.l Sp,spResult(A0) ; Point to it.
_sReadPRamRec ; Get pRAM.
Btst #spHas16bppACDC,SP_Flags(Sp) ; If we donÕt have an AC842A,
Beq.s @BadExit ; then just blow this off.
Btst #spAllow16bpp,SP_Flags(Sp) ; If we allowing 16bpp,
Bne.s @NotBlocked ; then return non-blocked state.
Move.b #1,csMode(A2) ; Otherwise, return blocked.
Bra.s @GoodExit
@NotBlocked Clr.b csMode(A2) ; Return enabled state.
@GoodExit Adda #SizesPRAMRec+spBlockSize,Sp ; Restore stack, and
Bra DAFBStatGood ; go home.
@BadExit Adda #SizesPRAMRec+spBlockSize,Sp ; Restore stack, and
Bra DAFBStatBad ; return error.
EndWith
DAFBGetPageMode
;---------------------------------------------------------------------
;
; Returns a boolean in csMode, set true if page mode is disabled.
;
;---------------------------------------------------------------------
With DAFBVidPrivates
Moveq #true32b,D0 ; Set up to switch into 32-bit mode,
_SwapMMUMode ; do switch, and
Move.b D0,-(Sp) ; save previous mode.
Move.l saveDAFBBase(A3),A0 ; Get DAFBBase into A0.
Move.l DAFB_PgMdEn(A0),D0 ; Get page mode.
Btst #0,D0 ; If page mode is on,
Bne.s @IsOn ; then return enabled state.
Move.b #1,csMode(A2) ; Otherwise, return disabled,
Bra.s @EndPageMode ; and leave.
@IsOn Clr.b csMode(A2) ; Return enabled state.
@EndPageMode Move.b (Sp)+,D0 ; Set up to switch back into previous mode,
_SwapMMUMode ; do switch, and
Bra DAFBCtlGood ; leave.
EndWith
DAFBGetAltSense
;---------------------------------------------------------------------
;
; Returns the alternate senseID code thatÕs in use. It
; should be noted that we cannot disguish between PAL &
; NTSC monitors & encoder boxes once DAFBSetAltSense has
; been called (because both the monitor & box codes are
; mapped into the same indexedSense code).
;
;---------------------------------------------------------------------
With spBlock,DAFBVidPrivates,SP_Params
;
; First, set up a slot parameter block on the stack.
;
Suba #spBlockSize,Sp ; Make a SpBlock on the stack.
Move.l Sp,A0 ; Get a pointer to it into A0.
Move.b dCtlSlot(A1),spSlot(A0) ; Set it up.
Clr.b spExtDev(A0)
;
; Next, read the current pRam so that we can determine whether the
; alternate senseID code is valid or not.
;
Suba #SizesPRAMRec,Sp ; Make an sPRAM block on the stack.
Move.l Sp,spResult(A0) ; Point to it.
_sReadPRamRec ; Get pRAM.
Clr.b csMode+1(A2) ; Assume the code already indexed for now.
Move.b SP_AltSense(Sp),D0 ; Get the alternate senseID byte.
Andi.b #spAltSenseValidMask,D0 ; If it is valid,
Bne.s @Valid ; return it.
Move.b #indexedNoConnect,csMode(A2) ; Otherwise, return the indexed no-connect code,
Bra.s @Exit ; and leave.
@Valid Move.b SP_AltSense(Sp),D0 ; Get the no-connect byte again.
Andi.b #spAltSenseMask,D0 ; Strip the validation code.
Cmp.b #indexedSenseVGA,D0 ; Is it the VGA code?
Bne.s @TryPal ; Nope, try PAL.
Move.b #extendedSenseVGA,D0
Bra.s @WriteExtended
@TryPal Cmp.b #indexedSensePAL,D0 ; Is it the PAL code?
Bne.s @TryLP ; Nope, try GoldFish.
Move.b #extendedSensePAL,D0
Bra.s @WriteExtended
@TryLP Cmp.b #indexedSenseLP,D0 ; Is it the GoldFish code?
Bne.s @Try19 ; Nope, try 19Ó.
Move.b #extendedSenseLP,D0
Bra.s @WriteExtended
@Try19 Cmp.b #indexedSense19,D0 ; Is it the 19Ó code?
Bne.s @TryRdRGB ; No, try the Radius ColorTPD.
Move.b #extendedSense19,D0
Bra.s @WriteExtended
@TryRdRGB Cmp.b #extended2PRdRGB,D0 ; Is it the ColorTPD.
Bne.s @TryRDMono ; Nope, try the Mono.
Bra.s @Write2PExtended
@TryRdMono Cmp.b #extended2PRdMono,D0 ; Is it the MonoTPD.
Bne.s @WriteIt ; Nope, assume indexed.
@Write2PExtended
Move.b #indexedSense2P,csMode+1(A2) ; Say code is type 3.
Bra.s @WriteIt
@WriteExtended Move.b #indexedNoConnect,csMode+1(A2) ; Say code is type 7.
@WriteIt Move.b D0,csMode(A2) ; Return valid monID.
@Exit Adda #SizesPRAMRec+spBlockSize,Sp ; Restore stack, and
Bra DAFBStatGood ; go home.
Endwith
;---------------------------------------------------------------------
;
; Exit from Control or Status.
;
; A0 = Ptr to param block.
; A1 = Ptr to AuxDCE.
; D0 = error code.
;
;---------------------------------------------------------------------
DAFBExitDrvr BTST #NoQueueBit,ioTrap(A0) ; no queue bit set?
BEQ.S DAFBGoIODone ; => no, not immediate
RTS ; otherwise, it was an immediate call
DAFBGoIODone MOVE.L JIODone,-(Sp) ; Get the IODone address,
Rts ; and go there.
;=====================================================================
;
; Utilities
;
;=====================================================================
;---------------------------------------------------------------------
;
; CalcScreenBaseAddr
;
; Returns the proper screen base address for the current page
; and mode.
;
; -> A3: Pointer to driver privates, saveMode(A3) must be set up!
;
DAFBCalcScreenBaseAddr
With DAFBVidPrivates,SpBlock,VPBlock
Movem.l A0-A1/D0,-(Sp) ; Save work registers.
Suba #spBlockSize,Sp ; Make a SpBlock on the stack.
Move.l Sp,A0 ; Get a pointer to it into A0.
Clr.b spSlot(A0) ; Say we want Slot 0.
Clr.b spID(A0) ; Start looking at spID 0.
Clr.b spExtDev(A0) ; (No external devices.)
Clr.b spTBMask(A0) ; Only look for DAFB video sResources.
Move.w #catDisplay,spCategory(A0) ; Look for: catDisplay,
Move.w #typVideo,spCType(A0) ; typVideo,
Move.w #drSwApple,spDrvrSW(A0) ; drSwApple,
Move.w #drHwDAFB,spDrvrHW(A0) ; drHWDAFB.
Clr.l spParamData(A0) ; (The video sResource must be enabled.)
Bset #foneslot,spParamData+3(A0) ; Limit search to slot 0.
_GetTypeSRsrc ; Get the spsPointer.
Move.w saveMode(A3),D0 ; Get the ID of the mode weÕre looking for.
Move.b D0,spID(A0) ; Look for this modeÕs parameters.
_sFindStruct ; Get the spsPointer.
Move.b #mVidParams,spID(A0) ; Look for the mVidParams.
_sGetBlock ; Grap Õem
Move.l spResult(A0),A0 ; Save a pointer the mVidParams.
Move.l saveBaseAddr(A3),A1 ; Get the active vRam base address.
Adda.l vpBaseOffset(A0),A1 ; Point to the base of the screen.
Move.l A1,saveScreenBase(A3) ; Save it.
_DisposPtr ; Dispose the mVidParams.
Adda #spBlockSize,Sp ; Restore the stack.
Movem.l (Sp)+,A0-A1/D0 ; Restore work registers.
Rts
Endwith
;---------------------------------------------------------------------
;
; Trans5to8
;
; The ACDC that supports 16bpp (AC842A) does so in a somewhat unique
; fashion. That is, it uses a sparse 8-bit CLUT. The
; translation forumla is as follows:
;
; 5-bits [4..0] -> 8-bits [4..04..2].
;
; <-> D1: 5-bit value to be converted into an 8-bit index.
;
DAFBTrans5to8
Move.l D0,-(Sp) ; Save D0 as scratch.
Moveq #0,D0 ; Clear it.
Move.w D1,D0 ; D1 = ---43210, D0 = ---43210.
Lsl.w #3,D1 ; D1 = 43210---, D0 = ---43210.
Lsr.w #2,D0 ; D1 = 43210---, D0 = -----432.
Or.w D0,D1 ; D1 = 43210432.
Move.l (Sp)+,D0 ; Restore D0.
Rts
;---------------------------------------------------------------------
;
; 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.
;
With DAFBVidParams
DAFBChkMode
Movem.l A0/D0/D2,-(Sp) ; Save work registers.
Sub.w #FirstVidMode,D1 ; Make mode zero-based.
Blt.s @ModeBad ; If the passed-in mode is < 0,
; then punt.
Btst #IsMono,GFlags(A3) ; If we donÕt have a mono-only display,
Beq.s @EndMonoChk ; then just go on.
Cmp.w #FifthVidMode-FirstVidMode,D1 ; If weÕre not trying for a direct mode,
Blt.s @EndMonoChk ; then just go on.
Bra.s @ModeBad ; Otherwise, punt.
@EndMonoChk
; For DAFB, all the ÔaÕ modes are even and all the ÔbÕ modes are odd, except
; for the convolved modes. So, if weÕre not a convolved mode, we just check
; the oddness or evenness of the spID to determine whether the passed in
; mode is OK. If itÕs a convolved mode, we will always be in the ÔbÕ configuration,
; but we just endcode that information into the vidParams table.
;
Move.l saveVidPtr(A3),A0 ; Get pointer to video params.
Adda.w #DVPMaxModeBase,A0 ; Point to MiscParams.
Move.b saveSlotID(A3),D0 ; Get functional sRsrcID of display.
Btst #0,D0 ; If the display is in ÔaÕ mode,
Beq.s @MakeA ; then say so.
Bra.s @MakeB ; Otherwise, make it a ÔbÕ mode.
@MakeA Moveq #0,D0 ; Say itÕs an ÔaÕ mode.
Bra.s @MaxMode
@MakeB Moveq #1,D0 ; Say itÕs a ÔbÕ mode.
@MaxMode Move.b D0,D2 ; Remember which mode we have.
Move.b (A0,D0),D0 ; Get maximum mode for the current display.
Cmp.b #FirstVidMode,D0 ; If itÕs already indexed,
Blt.s @ChkMode ; then just check it now.
Sub.b #FirstVidMode,D0 ; Otherwise, make max mode indexed.
Tst.b wombatFlag(A3) ; If we arenÕt on a Wombat,
Beq.s @16BppChk ; then just go on.
Cmp.w #indexedSenseRubik,saveMonID(A3) ; If we donÕt have a Rubik,
Bne.s @16BppChk ; then just go on.
Tst.b hasLin16BppCLUT(A3) ; If we donÕt have an Antelope,
Beq.s @16bppChk ; then just go on.
Subq #1,D0 ; Otherwise, adjust max-mode value
Bra.s @ChkMode ;
@16BppChk Btst #Has16bppSRsrc,GFlags(A3) ; If we have a 16bpp-capable sRsrc list
Bne.s @ChkMode ; then just go on.
Subq #1,D0 ; Otherwise, adjust max-mode value.
Tst.b D2 ; If weÕve got a ÔbÕ mode,
Bne.s @ChkMode ; then just go on.
Cmp.w #indexedSenseRubik,saveMonID(A3) ; If we donÕt have a Rubik,
Bne.s @ChkMode ; then just go on.
Subq #1,D0 ; Otherwise, adjust max-mode value.
@ChkMode Cmp.w D0,D1 ; If the passed in mode is > max mode,
Bgt.s @ModeBad ; then punt.
@ModeOK Cmp.w D1,D1 ; Set Eq when OK.
Bra.s @EndChkMode
@ModeBad Moveq #-1,D1 ; Set NEq when bad and invalidate D1.
@EndChkMode Movem.l (Sp)+,A0/D0/D2 ; Restore work registers.
Rts
Endwith
;---------------------------------------------------------------------
;
; Wait for vertical blanking. Interrupts are raised to level-2 around
; this routine.
;
; IMPORTANT! - This routine expects to be called in 32-bit addressing mode!!!!
;
; A1 = AuxDCE POINTER
; A3 = pointer to private storage
;---------------------------------------------------------------------
DAFBWaitVSync
MOVE.L A0,-(SP) ; Save work registers.
MOVE.L D0,-(SP) ; (Two MOVEs are faster than a MOVEM.)
MOVE.W SR,-(SP) ; Get the status register on stack.
MOVEQ #7,D0 ; Get mask into D0.
AND.B (SP),D0 ; Get the interrupt level.
SUBQ.B #2,D0 ;
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
Tst.w (Sp)+ ; Restore stack.
MOVE.L saveDAFBBase(A3),A0 ; Point to DAFB.
CLR.L Swatch_ClrCrsrInt(A0) ; Otherwise, clear the interrupt, just in case,
; since the interrupt handler
; canÕt get called here.
@WaitForVBL MOVE.L Swatch_IntStat(A0),D0 ; Get the VBL status.
BTST #dafbIntStatusBit,D0 ; If VBL has NOT occurred,
BEQ.S @WaitForVBL ; then just spin.
@Done MOVE.L (SP)+,D0 ; Restore work registers.
MOVE.L (SP)+,A0 ; (Two MOVEs are faster than a MOVEM.)
RTS
;---------------------------------------------------------------------
;
; SetDepth sets the DAFB frame buffer depth, and returns the
; frame buffer base in driver privates
;
; D1 contains the spID of the depth - $80 (the zero based mode ID)
; A1 = AuxDCE POINTER
; A2 = parameter block pointer
; A3 = dCtlStorage pointer
;
; Preserves all registers
;
;---------------------------------------------------------------------
DAFBSetDepth
WITH DAFBVidPrivates,DAFBVidParams,DAFBBppParams,SC_Params
MOVEM.L D0-D2/A0-A2,-(SP) ; save regs we are using
MOVE.L saveDAFBBase(A3),A2 ; get the DAFB base address
MOVE.L saveVidPtr(A3),A1 ; get a pointer to the screen depth parameters
MOVE.W D1,D2 ; copy the index
Btst #Has16bppSRsrc,GFlags(A3) ; If we have a 16bpp-capable sRsrc list
Bne.s @IndexOK ; then just go on.
Cmp.w #FifthVidMode-FirstVidMode,D2 ; If weÕre not trying to do 32bpp,
Bne.s @IndexOK ; then just go on.
Addq #1,D2 ; Otherwise, skip the 16bpp params.
@IndexOk MULU #DBPSize+SC_Size,D2 ; index to the correct parameter group
LEA DVPHdrSize(A1,D2),A1 ; point to the setup parameters
MOVEQ #true32b,D0 ; flip to 32-bit mode
_SwapMMUMode ;
MOVE.B D0,-(SP) ; save previous addressing mode
; Setup DAFBÉ
;
Tst.b wombatFlag(A3) ; If weÕre on a Wombat,
Bne.s @SetupDAFB ; then just go on.
Cmp.w #indexedSenseRubik,saveMonID(A3) ; If donÕt have a Rubik,
Bne.s @SetupDAFB ; then just go on.
Cmp.w #FirstVidMode-FirstVidMode,D1 ; If weÕre doing 1bpp,
Beq.s @Rubik1bpp ; set the weird base address.
Move.l #8,DAFB_VidBaseHi(A2) ; 2,4,8,16,32bpp-Rubik are std.
Bra.s @SetupDAFB
@Rubik1bpp
Move.l #7,DAFB_VidBaseHi(A2) ; 1bpp-Rubik is weird.
@SetupDAFB
DAFBWWrite dbpRowWords,DAFB_RowWords ; Set up the RowWords.
DAFBWWrite dbpConfig,DAFB_Config ; Set up the controller.
Move.l DAFB_ClkCfg(A2),D0 ; Pick up the ClkCfg reg.
Andi.l #$00000100,D0 ; Clear everything but the ClkSel bit.
DAFBWWrite dbpClkCfg,DAFB_ClkCfg ; Set up the clocking.
Or.l D0,DAFB_ClkCfg(A2) ; Make sure ClkSel is correct.
DAFBSpeedDR ; Reconfigure DAFB for the right CPU speed.
; Setup SwatchÉ
;
DAFBWWrite dbpTimingAdj,Swatch_TimeAdj ; Set up timing adjustments.
DAFBWWrite dbpHSerr,Swatch_HSerr ; Set up horizontal timing.
DAFBWWrite dbpHlfLn,Swatch_HlfLn ;
DAFBWWrite dbpHEq,Swatch_HEq ;
DAFBWWrite dbpHSP,Swatch_HSP ;
DAFBWWrite dbpHBWay,Swatch_HBWay ;
DAFBWWrite dbpHBrst,Swatch_HBrst ;
DAFBWWrite dbpHBP,Swatch_HBP ;
DAFBWWrite dbpHAL,Swatch_HAL ;
DAFBWWrite dbpHFP,Swatch_HFP ;
DAFBWWrite dbpHPix,Swatch_HPix ;
; Setup ACDCÉ
;
Clr.l ACDC_AddrReg(A2) ; Tell ACDC to use PCBR0.
DAFBWWrite dbpACDCPCBR,ACDC_ConfigReg ; Set up ADCD config register.
Nop ; (DAFBÕs address space is non-serial.)
Tst.l ACDC_AddrReg(A2) ; Read the addr reg to make it stick (AC842A).
Btst #has16bppSRsrc,GFlags(A3) ; If we donÕt have a 16bpp-capable sRsrc,
Beq.s @EndDAFB16bpp ; then skip the 16bpp setup.
Cmp.w #FifthVidMode-FirstVidMode,D1 ; If we arenÕt doing 16bpp, then
Bne.s @EndDAFB16bpp ; just go on.
Move.l #1,ACDC_AddrReg(A2) ; Tell ACDC to use PCBR1.
Move.l #$C0,ACDC_ConfigReg(A2) ; Switch to 16bpp.
Nop ; (DAFBÕs address space is non-serial.)
Tst.l ACDC_AddrReg(A2) ; Read the addr reg to make it stick (AC842A).
Clr.l ACDC_AddrReg(A2) ; Tell ACDC to use PCBR0 again.
@EndDAFB16bpp
; AC842A adjustments. There are a bunch of NOPs in the code below, and thereÕs a good reason for
; them. It turns out that DAFBÕs address space on the Quadras is non-serial, which means
; the order of reads and writes is somewhat non-deterministic. Unfortunately, in order
; to program the AC842A, certain writes MUST precede certain reads, and vice-versa. So,
; to get around this problem, I have strategically placed various NOPs below. On Õ040Õs,
; the NOP actually has a function, which is to force pending writes to occur before
; reads. Cool, huh!
;
Tst.b has16bppACDC(A3) ; If we donÕt have an AC842A,
Beq @DoReset ; then just go on.
Move.l DAFB_ClkCfg(A2),D0 ; Get the current clock configuration.
Bfextu D0{dafbPixSel1:1},D2 ; Get PIXSEL1 (PIXSEL1 -> ~acdcPCS).
Not.l D2 ; Invert it.
Clr.l ACDC_AddrReg(A2) ; Tell ACDC to use PCBR0.
Nop ; (DAFBÕs address space is non-serial.)
Move.l ACDC_ConfigReg(A2),-(Sp) ; Save PCBR0 for later.
Move.l #6,ACDC_ConfigReg(A2) ; Put ACDC into indirect mode.
Move.l #1,ACDC_AddrReg(A2) ; Tell ACDC to use PCBR1.
Nop ; (DAFBÕs address space is non-serial.)
Move.l ACDC_ConfigReg(A2),D0 ; Save the current configuration.
Bfins D2,D0{acdcPCS:1} ; Set up to select the right clock.
Move.l D0,ACDC_ConfigReg(A2) ; Write PCBR1 back out with correct clock set.
Nop ; (DAFBÕs address space is non-serial.)
Tst.l ACDC_AddrReg(A2) ; Read the addr reg to make it stick (AC842A).
Clr.l ACDC_AddrReg(A2) ; Tell ACDC to use PCBR0 again.
Move.l (Sp)+,ACDC_ConfigReg(A2) ; Restore PCBR0.
Tst.b wombatFlag(A3) ; If we have a WombatDAFB, then just
Bne.s @DoSwatchAdj ; go on (because we ONLY use the programmble clock).
Btst #0,D2 ; If PIXSEL1 was NOT zero,
Beq.s @DoSwatchAdj ; then just go on.
Move.l DAFB_ClkCfg(A2),D0 ; Get the current clock configuration.
Bfins D2,D0{dafbPixSel0:1} ; Set up PIXSEL0 so thatÉ
Move.l D0,DAFB_ClkCfg(A2) ; Éthe programmable clock is used.
@DoSwatchAdj
Tst.b wombatFlag(A3) ; If weÕre on a Wombat,
Bne.s @StrtAdj1 ; then just go on.
Move.l saveVidPtr(A3),A0 ; Pick up the vidParams pointer.
Cmp.b dvpBadDepth(A0),D1 ; If weÕre not switching to a ÒbadÓ depth,
Bne.s @StrtAdj1 ; then just go on.
DAFBWWrite dbpTimingAdjAMD,Swatch_TimeAdj ; Adjust TimingAdj.
Move.l Swatch_TimeAdj(A2),D0 ; Get the adjusted value.
Add.b dvpFudge(A0),D0 ; Adjust it some more.
Move.l D0,Swatch_TimeAdj(A2) ; Write it back out.
Bra.s @StrtAdj2 ; And go on.
@StrtAdj1 DAFBWWrite dbpTimingAdjAMD,Swatch_TimeAdj ; Adjust TimingAdj,
@StrtAdj2 DAFBWWrite dbpHALAMD,Swatch_HAL ; HAL,
DAFBWWrite dbpHFPAMD,Swatch_HFP ; HFP
Tst.b wombatFlag(A3) ; If weÕre not on a Wombat,
Beq.s @DoReset ; then just go on
Moveq #0,D0 ; Clear this reg.
Move.w dbpACDCPCBR(A1),D0 ; Pick up the PCBR value.
Bclr #7,D0 ; Strip off the IRE-value.
Lsr.w #5,D0 ; Keep just the VidClk bits.
Move.w D0,D2 ; And save them for later.
Lea DAFBWombatTimingAdjTbl,A0 ; Point to the Wombat TimingAdj table.
Mulu #DAFBWombatTSize,D0 ; Figure out the offset value.
Adda.w D0,A0 ; Point to the right entry.
Move.w (A0,D1*2),D0 ; Pick up the appropriate value.
Add.l D0,Swatch_TimeAdj(A2) ; Add it in.
Tst.b hasLin16BppCLUT(A3) ; If we donÕt have an Antelope,
Beq.s @EndSwatchAdj ; then just go on.
Lea DAFBAntelopeTbl,A0 ; Point to the table of Antelope adjustment values.
Move.w (A0,D2*2),D0 ; Get the appropriate adjustment value.
Add.l D0,Swatch_TimeAdj(A2) ; Adjust TimingAdj,
Add.l D0,Swatch_HAL(A2) ; HAL,
Add.l D0,Swatch_HFP(A2) ; HFP.
Cmp.w #FifthVidMode-FirstVidMode,D1 ; If we arenÕt doing 16bpp, then
Bne.s @EndSwatchAdj ; just go on.
Cmp.w #indexedSensePAL,saveMonID(A3) ; If we arenÕt doing PAL FF/ST, then
Bne.s @EndSwatchAdj ; just go on.
Addi.l #1,Swatch_TimeAdj(A2) ; Otherwise, adjust TimingAdj again.
@EndSwatchAdj
; Sync On GreenÉ (Wombat only)
;
Move.l DAFB_ClkCfg(A2),D0 ; Get the current Clock config value.
Btst #syncOnGreen,GFlags(A3) ; If weÕre supposed to put sync on green,
Bne.s @EnableSyncOnGreen ; then hop to it.
Moveq #0,D1 ; Otherwise, set up for disabling.
Bra.s @SyncOnGreenCommon
@EnableSyncOnGreen
Moveq #1,D1 ; Set up for enabling.
@SyncOnGreenCommon
Bfins D1,D0{dafbSyncOnGreen:1} ; Toggle the sync-on-green bit appropriately,
Move.l D0,DAFB_ClkCfg(A2) ; apply it.
; Everything's configured, so do the DAFB reset sequence after waiting for vSync to happen.
;
@DoReset
Move.w Sr,-(Sp) ; Save the current interrupt level.
BSR DAFBWaitVSync ; Wait for the next VBL.
Move.w (Sp)+,Sr ; Restore the interrupt level.
DAFBReset ; Reset DAFB.
MOVE.B (SP)+,D0 ; get the previous addressing mode back
_SwapMMUMode ;
MOVEM.L (SP)+,D0-D2/A0-A2 ; restore all regs
RTS ; return
ENDWITH
;---------------------------------------------------------------------
;
; 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.
;
; D1 = spID of screen depth - FirstVidMode
; A3 = driver private storage
;
; All registers are preserved
;
With DAFBVidParams,DAFBBppParams,SC_Params
DAFBGrayScreen
MOVEM.L A0-A2/D0-D7,-(SP)
MOVE.L saveBaseAddr(A3),A2 ; Get the screen base address into A2.
Move.w D1,D7 ; Save the vidMode for later.
Move.b saveSlotId(A3),D3 ; Get the functional sRsrcID.
Btst #has16bppSRsrc,GFlags(A3) ; If we have a 16bpp sRsrc,
Bne.s @GetXPats ; then get the extended patterns.
Bra.s @NormPats ; Otherwise, just use the normal patterns.
@GetXPats Lea DAFBXPats,A0 ; Point to the table of patterns,
Move.l (A0,D1*4),D4 ; and load the right one.
Move.l D4,D5 ; Copy the pattern for the double-long stuff.
MOVEQ #IndexedBlack,D6 ; assume an indexed mode for now
Cmp.w #FifthVidMode-FirstVidMode,D1 ; If this is not a direct mode,
Blt.s @StartGray ; just go on.
Cmp.w #FifthVidMode-FirstVidMode,D1 ; If this is 16bpp mode, then
Beq.s @Skip32bpp ; the data fits into one long.
Not.l D5 ; Otherwise, invert this half for white.
@Skip32bpp Moveq #DirectBlack,D6 ; Set black as direct.
Cmp.b #sRsrc_Vid_DAFB_NTSCSTax,D3 ; If this is an NTSC ST (non-convolved) display,
Beq.s @StartGray ; then donÕt alter the baseAddr.
Cmp.b #sRsrc_Vid_DAFB_NTSCSTbx,D3 ;
Beq.s @StartGray ;
Cmp.b #sRsrc_Vid_DAFB_PALSTax,D3 ; If this is a PAL ST (non-convolved) display,
Beq.s @StartGray ; then donÕt alter the baseAddr.
Cmp.b #sRsrc_Vid_DAFB_PALSTbx,D3 ;
Beq.s @StartGray ;
@AdjBase Move.l saveScreenBase(A3),A2 ; Get the (offset, ugh!) screen base address,
Bra.s @StartGray ; and start graying.
@NormPats LEA DAFBPats,A0 ; point to the pattern table
MOVE.L (A0,D1*4),D4 ; get the graying pattern
MOVE.L D4,D5 ; copy it
MOVEQ #IndexedBlack,D6 ; assume an indexed mode for now
CMP.W #FifthVidMode-FirstVidMode,D1 ; is this Millions mode?
BNE.S @StartGray ; if so, use the special graying routine
NOT.L D5 ; invert this half to make white
MOVEQ #DirectBlack,D6 ; nope, get direct instead
@StartGray MOVE.L saveVidPtr(A3),A1 ; point to video parameters
Move.l A1,A0 ; Make a copy.
Btst #has16bppSRsrc,GFlags(A3) ; If we have a 16bpp-capable sRsrc list
Bne.s @IndexOK ; then just go on.
Cmp.w #FifthVidMode-FirstVidMode,D1 ; If weÕre not trying to do 32bpp,
Bne.s @IndexOK ; then just go on.
Addq #1,D1 ; Otherwise, skip the 16bpp params.
@IndexOK MULU #DBPSize+SC_Size,D1 ; index to the correct parameter group
LEA DVPHdrSize+DBPSize(A1,D1),A1 ; point to the screen graying parameters
MOVEQ #true32b,D0 ; flip to 32-bit mode
_SwapMMUMode ;
MOVE.B D0,D2 ; save previous addressing mode
; Do top of screenÉ
;
; Note that SC_BorderHeight is adjusted to work correctly for both bordered and non-bordered screens.
; Specifically, this constant is not Ò-1Ó-adjusted for Dbra, so we jump into the tail end of the Dbra
; loop and therefore have the ÒrightÓ thing happen. My head hurts now, and I hope yours does.
;
Cmp.w #indexedSenseRubik,saveMonID(A3) ; If weÕre on a Rubik display, then
Beq.s @FixRubik1bpp ; see if wee need to do fix.
Cmp.b #sRsrc_Vid_DAFB_NTSCconvST,D3 ; If weÕre on an NTSC convolved display,
Beq.s @FixNTSCPALTop ; then apply fix.
Cmp.b #sRsrc_Vid_DAFB_NTSCconvFF,D3
Beq.s @FixNTSCPALTop
Cmp.b #sRsrc_Vid_DAFB_NTSCconvSTx,D3
Beq.s @FixNTSCPALTop
Cmp.b #sRsrc_Vid_DAFB_NTSCconvFFx,D3
Beq.s @FixNTSCPALTop
Cmp.b #sRsrc_Vid_DAFB_PALconvST,D3 ; If weÕre on a PAL convolved display,
Beq.s @FixNTSCPALTop ; then apply fix.
Cmp.b #sRsrc_Vid_DAFB_PALconvFF,D3
Beq.s @FixNTSCPALTop
Cmp.b #sRsrc_Vid_DAFB_PALconvSTx,D3
Beq.s @FixNTSCPALTop
Cmp.b #sRsrc_Vid_DAFB_PALconvFFx,D3
Beq.s @FixNTSCPALTop
Bra.s @ScreenStart
@FixRubik1bpp
Move.w #DAFB_512_RB,D0 ; Fix first-line problem on Rubik displays.
Bra.s @FixRow ; (Only really need to this in 1bpp mode, but doesnÕt hurt others.)
@FixNTSCPALTop
Move.w #DAFB_1024_RB,D0 ; Create ÒfalseÓ first line on NTSC/PAL convolved displays.
@FixRow Suba D0,A2 ; Point back one full line.
Lsr.w #2,D0 ; Make loop counter long-word based.
Subq #1,D0 ; Subtract 1 for Dbra.
@BlastRow Move.l D6,(A2)+ ; Write black out.
Dbra D0,@BlastRow
@ScreenStart
Move.w SC_BorderHeight(A1),D1 ; get number of rows (not -1) to blast back on top
Bra.s @TopSecPrime ;
@TopSecFill_V
Move.w SC_BorderWidth(A1),D0 ; get number of longs (-1) to blast black in row
@TopSecFill_H
Move.l D6,(A2)+ ; blast black to screen
Dbra D0,@TopSecFill_H
Adda.w SC_SkipFactor(A1),A2 ; skip to start of next row
@TopSecPrime
Dbra D1,@TopSecFill_V
; Do middle of screenÉ
;
; Unlike the top part, there is always a Òmiddle.Ó However, there might be a left and right side (when the
; border is appropriate), so the not Ò-1Ó-adjusted for Dbra comments that are listed above apply horizontally
; here.
;
Move.w dvpNumRows(A0),D1 ; get number of rows (-1) in middle of screen
@MidSecFill_V
Move.w SC_BorderSide(A1),D0 ; get number of longs (not -1) to blast black in row
Bra.s @MidSecPrime_L
@MidSecFill_L
Move.l D6,(A2)+ ; blast black to screen
@MidSecPrime_L
Dbra D0,@MidSecFill_L
Move.w SC_ActiveWidth(A1),D0 ; get the number of doublelongs (-1) for active middle
@MidActFill_H
Move.l D4,(A2)+ ; Fill the active section with gray
Cmp.b #sRsrc_Vid_DAFB_SVGAa,D3 ; Skip if SuperVGA (800x600 is not an
Beq.s @ChkMode ; even multiple of 64, but it is an)
Cmp.b #sRsrc_Vid_DAFB_SVGAb,D3 ; even multiple of 32).
Beq.s @ChkMode ;
Cmp.b #sRsrc_Vid_DAFB_SVGAax,D3 ;
Beq.s @ChkMode ;
Cmp.b #sRsrc_Vid_DAFB_SVGAbx,D3 ;
Beq.s @ChkMode ;
Bra.s @DoDouble ;
@ChkMode Btst #has16bppSRsrc,GFlags(A3) ; If we have a 16bpp-capable sRsrc,
Bne.s @16bppSRsrc ; then go there.
Cmp.w #FifthVidMode-FirstVidMode,D7 ; If weÕre not doing 32bpp,
Bne.s @SkipDouble ; then really skip.
Bra.s @DoDouble ; Otherwise, do second half.
@16bppSRsrc Cmp.w #SixthVidMode-FirstVidMode,D7 ; If weÕre not doing 32bpp,
Bne.s @SkipDouble ; then really skip.
@DoDouble Move.l D5,(A2)+ ; Otherwise, do second half where applicable.
@SkipDouble Dbra D0,@MidActFill_H
Not.l D4 ; Invert for next line, and
Not.l D5 ; second half if applicable.
Move.w SC_BorderSide(A1),D0 ; get number of longs (not -1) to blast black in row
Bra.s @MidSecPrime_R
@MidSecFill_R
Move.l D6,(A2)+ ; blast black to screen
@MidSecPrime_R
Dbra D0,@MidSecFill_R
Add.w SC_SkipFactor(A1),A2 ; move to NEXT line
Dbra D1,@MidSecFill_V
; Do bottom of screenÉ
;
Move.w SC_BorderHeight(A1),D1 ; Get number of rows (not -1) to blast back on bottom.
Cmp.b #sRsrc_Vid_DAFB_NTSCconvST,D3 ; If weÕre on an NTSC convolved display,
Beq.s @FixNTSCPALBot ; then apply fix.
Cmp.b #sRsrc_Vid_DAFB_NTSCconvFF,D3
Beq.s @FixNTSCPALBot
Cmp.b #sRsrc_Vid_DAFB_NTSCconvSTx,D3
Beq.s @FixNTSCPALBot
Cmp.b #sRsrc_Vid_DAFB_NTSCconvFFx,D3
Beq.s @FixNTSCPALBot
Cmp.b #sRsrc_Vid_DAFB_PALconvST,D3 ; If weÕre on a PAL convolved display,
Beq.s @FixNTSCPALBot ; then apply fix.
Cmp.b #sRsrc_Vid_DAFB_PALconvFF,D3
Beq.s @FixNTSCPALBot ; then apply fix.
Cmp.b #sRsrc_Vid_DAFB_PALconvSTx,D3
Beq.s @FixNTSCPALBot
Cmp.b #sRsrc_Vid_DAFB_PALconvFFx,D3
Beq.s @FixNTSCPALBot
Bra.s @BotStart
@FixNTSCPALBot
Addq #1,D1 ; For convolved interlace displays, we need to
; blacken the ÒfalseÓ bottom.
@BotStart
Bra.s @BotSecPrime ;
@BotSecFill_V
Move.w SC_BorderWidth(A1),D0 ; get number of longs (-1) to blast black in row
@BotSecFill_H
Move.l D6,(A2)+ ; blast black to screen
Dbra D0,@BotSecFill_H
Adda.w SC_SkipFactor(A1),A2 ; skip to start of next row
@BotSecPrime
Dbra D1,@BotSecFill_V
MOVE.B D2,D0 ; get the previous addressing mode back
_SwapMMUMode ;
@GrayExit
MOVEM.L (SP)+,A0-A2/D0-D7 ; restore all regs
RTS ; and return
Endwith
;---------------------------------------------------------------------
;
; DAFBDirectCLUTSet writes gamma-corrected ascending grayscale ramps into
; the CLUT
;
; A3 = dCtlStorage pointer
;
; Preserves all registers used.
;
;---------------------------------------------------------------------
DAFBDirectCLUTSet
MOVEM.L D0-D3/D5/A0/A4-A6,-(SP) ; save registers
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
CMP.W #1,gChanCnt(A0) ; if only only one table, we're set
BEQ.S @OneTbl ; => just one table
MOVE gDataWidth(A0),D1 ; get width of each entry in bits
ADDQ #7,D1 ; round to nearest byte
LSR #3,D1 ; get bytes per entry
MULU gDataCnt(A0),D1 ; get size of table in bytes
ADDA D1,A5 ; calc base of green
ADDA D1,A6 ; calc baseÉ
ADDA D1,A6 ; Éof blue
@OneTbl MOVE.W gDataCnt(A0),D2 ; Get number of entries.
Subq #1,D2 ; Make it zero based.
MOVEQ #true32b,D0 ; flip to 32-bit mode
_SwapMMUMode ;
MOVE.L saveVDACBase(A3),A0 ; point to the hardware
ADDA #ACDC_DataReg,A0 ; point to data register
CLR.L ACDC_AddrReg-ACDC_DataReg(A0) ; start at the beginning of CLUT
Move.w GFlags(A3),D5 ; Get the flags for quick access.
Btst #has16bppSRsrc,D5 ; If we have a 16bpp-capable sRsrc,
Bne.s @Chk16bpp ; then check for 16bpp.
Bra.s @Normbpp ; Otherwise, just do the normal stuff.
@Chk16bpp Move.w saveMode(A3),D1 ; Get the current mode.
Cmp.b #FifthVidMode,D1 ; If weÕre not doing 16bpp,
Bne.s @Normbpp ; then go on.
Bset #UseTrans,D5 ; Remember to do 5-to-8 bit translation stuff.
Move.w #$1F,D2 ; There are only 32 entries to whack in 16bpp mode.
@Normbpp MOVE.W SR,-(SP) ; preserve the status register
BSR DAFBWaitVSync ; wait for next blanking period (preserves A0/D0)
; Write an incrementing grayscale ramp.
Moveq #0,D3 ; Init ramp start.
Moveq #0,D1 ; Init trans index (will be used as a long).
@Repeat Move.w D3,D1 ; Get the current ramp/index value.
Btst #UseTrans,D5 ; If we donÕt need to translate this value,
Beq.s @Index ; then just go on.
Bsr DAFBTrans5to8 ; Otherwise, translate from 5-bits to 8.
Tst.b hasLin16BppCLUT(A3) ; If the CLUT/DAC itself doesnÕt need translating,
Bne.s @Index ; then just go on.
Move.l D1,ACDC_AddrReg-ACDC_DataReg(A0) ; Otherwise, use the 5-to-8 index for the Clut address.
@Index MOVE.B (A4,D1),3(A0) ; Write gamma-corrected red,
MOVE.B (A5,D1),3(A0) ; green, and
MOVE.B (A6,D1),3(A0) ; blue.
ADDQ #1,D3 ; increment ramp/index value
DBRA D2,@Repeat ;
MOVE.W (SP)+,SR ; restore the status reg
_SwapMMUMode ;
MOVEM.L (SP)+,D0-D3/D5/A0/A4-A6 ; restore saved registers
RTS
;-------------------------------------------------------------
; The Interrupt handler for the DAFB Built-In Video
;-------------------------------------------------------------
; On entry A1 contains the pointer to the driver's private storage
DAFBBeginIH
Move.l A0,-(Sp) ; Save A0/D1 due to direct jump to SwapMMUMode.
Move.l D1,-(Sp) ; (Two Moves are faster than a Movem.)
Moveq #true32b,D0 ; Set up to swap into 32-bit mode.
Jsr ([jSwapMMU]) ; Do fast swap.
Move.b D0,-(Sp) ; Save the previous addressing mode.
Move.l saveDAFBBase(A1),A0 ; Point to the DAFB baseAddr.
@WaitForClr Clr.l Swatch_ClrCrsrInt(A0) ; Clear this interrupt.
Move.l Swatch_IntStat(A0),D0 ; Get its status.
Btst #dafbIntStatusBit,D0 ; If itÕs not cleared yet,
Bne.s @WaitForClr ; then just spin.
Move.b (Sp)+,D0 ; Set up to swap back into previous addressing mode.
Jsr ([jSwapMMU]) ; Do fast swap.
Moveq #0,D0 ; Set up for Slot $0É
Jsr ([jVBLTask]) ; Éand call the VBL Task Manager.
Moveq #1,D0 ; Signal that the interrupt was serviced
Move.l (Sp)+,D1 ; Restore A0/D1 registers.
Move.l (Sp)+,A0 ; (Two Moves are faster than a Movem.)
Rts ; Return to caller.
END