; ; 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): ; ; 08-03-93 jmp Changed the reference names of the multiscan display constants ; to their new names. ; 11/5/92 SWC Changed VideoEqu.a->Video.a and ShutdownEqu.a->Shutdown.a. ; 11/2/92 kc Don't include SonicEqu.a. ; 10-29-92 jmp (jmp,H26) Fixed a branching problem in the PageMode ; enabling/disabling code in VidOpen. ; 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…. ; 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. ; 10/6/92 GDW New location for ROMLink tool. ; ——————————————————————————————————————————————————————————————————————————————————————— ; Pre-ROMLink comments begin here. ; ——————————————————————————————————————————————————————————————————————————————————————— ; 09-29-92 jmp (jmp,H23) Added about a 1-µSec delay between SetEntries R-G-B ; writes to the Antelope CLUT/DAC (i.e., unlike the Brooktree and ; AMD CLUT/DACs, the Antelope parts don’t use dual-ported RAM ; internally). ; (jmp,H22) The TimingAdj register wasn’t being set up properly in ; PAL 16bpp FF/ST with Antelope parts. Fixed this. ; (jmp,H21) Added more support for the Antelope (AT&T/Sierra) ; CLUT/DAC used on Wombat/WLCD. ; 09-03-92 jmp (jmp,H20) Added initial support for the AT&T CLUT/DAC to be used ; in Wombat/WLCD systems. ; 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. ; 6/18/92 KW (jmp,H13) Eliminated yet even more of the old DAFBVidParams ; fields, so I adjusted the code accordingly. ; 6/4/92 KW (jmp,H12) Fixed a problem where I wasn’t setting up the timing ; adjust register in the Brooktree DAC case. Oops! (jmp,H11) Made ; the code that deals with the DAFB vidParams “smarter” due my ; compacting vidParams tables. This kind of work will continue ; throughout Wombat development. (jmp,H10) Cleaned up the ; interrupt handler a little, cleaned up WaitVSync a little, fixed ; the “little table of counts” problem from Zydeco, etc…. ; 5/16/92 kc Roll in Horror Changes. Comments follow: ; 02/20/92 jmp (jmp,Z51) Fixed a problem in the SetDepth where I wasn’t always ; selecting the correct clock. This problem surfaced due to a ; change in the AC824A (aka AC823). ; 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.” ; 01/11/92 jmp Added rudimentary support for the newly-defined extended sense ; codes. ;
12/17/91 jmp Eliminated some code in GrayScreen that handled base addresses ; that moved across depths, as it is no longer needed. ;
11/25/91 jmp The vidParams moved from the functional to the board sRsrc to ; save space -- updated the driver accordingly. ;

11/12/91 jmp Quit forcing the bitdepth back to 1bpp in SetDefaultMode. ;

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