sys7.1-doc-wip/DeclData/DeclVideo/DAFB/DAFBDriver.a
2019-07-27 22:37:48 +08:00

3399 lines
130 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;
; 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 dont use dual-ported RAM
; internally).
; (jmp,H22) The TimingAdj register wasnt 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 wasnt 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 wasnt 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 its 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 didnt 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 didnt 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 Wasnt cleaning up the stack on exit from GetEntries input
; errors. VidReset want passing the right value to DAFBSetDepth
; (i.e., indexed mode value vs. bpp value). And GetPage wasnt
; 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 CTabHandles MasterPointer as a Pointer.
; Optimizations: Tightened up the WaitVSync code; changed several
; Move.bs and Move.ws to Moveqs 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.ws instead of Cmp.bs.
; <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 doesnt 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 (wasnt 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 StripAddressing 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
; doesnt 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 DAFBs 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 dont 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 weve 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 (its byte sized).
Move.b SP_MonID(Sp),D2 ; Get the monID (its 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 were 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 dont have an AC842A,
Beq.s @CheckPageMode ; then go on.
Move.b #1,has16bppACDC(A3) ; Otherwise, say we do.
Btst #spHas16bppSRsrc,D1 ; If we dont 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 were 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 were not on a Wombat,
Beq.s @ChkCLUTType ; then just go on.
Move.b #1,wombatFlag(A3) ; Otherwise, say were on a Wombat.
@ChkCLUTType Btst #wLin16Bpp,D0 ; If we dont have an Antelope,
Beq.s @ChkVidEnb ; then just go on.
Move.b #1,hasLin16BppCLUT(A3) ; Otherwise, say weve 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, were 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 were 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 were 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 (doesnt 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 theres only one table,
Beq.s @OnlyOneTable ; then were 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 its out of
Bmi DAFBSEBadExit ; range.
;
; In order to support Vesuvio & the RGB Portraits 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 ; CTabHandles 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 arent 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 were 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 were translating.
Bclr #UseSeq,D5 ; If were 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 users data. But all the previous Apple video drivers
; have done the same thing here, so well 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 were 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 dont 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 dont 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 its 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
; DAFBs 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 wont 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 sRsrcs
(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 its not catDisplay,
Bne.s @BadExit ; then quit.
Move.w spCType(A0),D0 ; Get the type.
Cmp.w #typVideo,D0 ; If its not typVideo,
Bne.s @BadExit ; then quit.
Move.w spDrvrSw(A0),D0 ; Get the software kind.
Cmp.w #drSwApple,D0 ; If its not drSwApple,
Bne.s @BadExit ; then quit.
Move.w spDrvrHw(A0),D0 ; Get the hardware ID.
Cmp.w #drHwDAFB,D0 ; If its 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 were not in a direct mode,
Beq.s @WriteIt ; just go on.
Move.b csMode(A2),D0 ; Get the mode were going to.
Cmp.b #sRsrc_Vid_DAFB_NTSCconvSTx,D0 ; If were 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 were already NOT putting sync on green,
Beq.s @Done ; then theres 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 were already putting sync on green,
Bne.s @Done ; then theres 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 were 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 were 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 isnt.
;
; 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 dont 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 dont 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 were 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 its the Radius ColorTPD,
Beq @WriteIt ; then write it out.
Cmp.b #extended2PRdMono,D1 ; If its the Radius MonoTPD,
Beq.s @WriteIt ; then write it out.
Bra @MonIDNotValid ; Otherwise, return an error.
@HRExtended
Cmp.b #extendedHR,csMode(A2) ; If its 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 its 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 its 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 users data. But all the previous Apple video drivers
; have done the same thing here, so well 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 were 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 were 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 dont 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 thats 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 were looking for.
Move.b D0,spID(A0) ; Look for this modes 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 dont have a mono-only display,
Beq.s @EndMonoChk ; then just go on.
Cmp.w #FifthVidMode-FirstVidMode,D1 ; If were 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 were not a convolved mode, we just check
; the oddness or evenness of the spID to determine whether the passed in
; mode is OK. If its 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 its an a mode.
Bra.s @MaxMode
@MakeB Moveq #1,D0 ; Say its 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 its 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 arent on a Wombat,
Beq.s @16BppChk ; then just go on.
Cmp.w #indexedSenseRubik,saveMonID(A3) ; If we dont have a Rubik,
Bne.s @16BppChk ; then just go on.
Tst.b hasLin16BppCLUT(A3) ; If we dont 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 weve got a b mode,
Bne.s @ChkMode ; then just go on.
Cmp.w #indexedSenseRubik,saveMonID(A3) ; If we dont 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
; cant 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 were 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 were on a Wombat,
Bne.s @SetupDAFB ; then just go on.
Cmp.w #indexedSenseRubik,saveMonID(A3) ; If dont have a Rubik,
Bne.s @SetupDAFB ; then just go on.
Cmp.w #FirstVidMode-FirstVidMode,D1 ; If were 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 ; (DAFBs 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 dont have a 16bpp-capable sRsrc,
Beq.s @EndDAFB16bpp ; then skip the 16bpp setup.
Cmp.w #FifthVidMode-FirstVidMode,D1 ; If we arent 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 ; (DAFBs 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 theres a good reason for
; them. It turns out that DAFBs 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 040s,
; the NOP actually has a function, which is to force pending writes to occur before
; reads. Cool, huh!
;
Tst.b has16bppACDC(A3) ; If we dont 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 ; (DAFBs 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 ; (DAFBs 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 ; (DAFBs 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 were 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 were 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 were 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 dont 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 arent doing 16bpp, then
Bne.s @EndSwatchAdj ; just go on.
Cmp.w #indexedSensePAL,saveMonID(A3) ; If we arent 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 were 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 dont 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 dont 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 were 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 were on a Rubik display, then
Beq.s @FixRubik1bpp ; see if wee need to do fix.
Cmp.b #sRsrc_Vid_DAFB_NTSCconvST,D3 ; If were 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 were 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 doesnt 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 were not doing 32bpp,
Bne.s @SkipDouble ; then really skip.
Bra.s @DoDouble ; Otherwise, do second half.
@16bppSRsrc Cmp.w #SixthVidMode-FirstVidMode,D7 ; If were 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 were 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 were 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 were 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 dont 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 doesnt 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 its 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