; ; File: JMFBDriver.a ; ; Contains: Driver for 4¥8/8¥24 Cards. ; ; Written by: Casey King/Mike Puckett ; ; Copyright: © 1986-1992 by Apple Computer, Inc. All rights reserved. ; ; This file is used in these builds: Mac32 ; ; ; Change History (most recent first): ; ; 11/18/92 SWC Changed SlotEqu.a->Slots.a and VideoEqu.a->Video.a. ; <1> 1/7/92 RB first checked in ; =============== Terror History ======================== ; ; <4> 6/17/91 jmp Fixed a Òmemory leakÓ bug in SetGamma when changing the size of ; the current gamma table (i.e., form size 3 to 1, or vice-versa). ; Also, eliminated support for PAL displays & encoder boxes since ; the versions of the 4¥8 & 8¥24 cards that weÕre patching out ; donÕt have the sRsrcs. ; <3> 4/4/91 jmp Cleaned up the conditional assembly stuff (i.e., now use ForRom ; instead of PadForOverPatch). ; <2> 2/25/91 jmp Rolled in CaseyÕs latest changes. ; <1> 01/06/91 jmp Checked into TERROR ROM for the first time. ; <0> 11/19/90 jmp Formatted for use with TERROR ROM (as opposed to a ; declaration ROM). ;------------------------------------------------------------------- ; ; (c) Apple Computer, Inc. 1986-1990 ; All rights reserved. ; ;------------------------------------------------------------------- ; File : ElmerDrvr.a ; Author : Casey King (based extensively on Bob and Blackjack) ;------------------------------------------------------------------- ; This file contains the video driver for use by the Macintosh ; OS. It is structured as a normal Mac slot device driver. ; ;------------------------------------------------------------------- ; Mod History : ; Refer to Projector change history for revision details ;------------------------------------------------------------------- BLANKS ON STRING ASIS MACHINE MC68020 LOAD 'StandardEqu.d' Print Off INCLUDE 'ColorEqu.a' INCLUDE 'ROMEqu.a' INCLUDE 'Slots.a' INCLUDE 'Video.a' INCLUDE 'JMFBDepVideoEqu.a' Print On If ForRom Then JMFBDrvr Proc Export Else VideoDrvr Main Export Endif ;------------------------------------------------------------------- ; Equates for privates have been moved to efdepvideoequ.a since ; one of the values is used in SecondaryInit.a and cannont be ; forward referenced. They are duplicated here for convenience. ;------------------------------------------------------------------- ; This is device storage which is stored in the dCtlStorage field of the DCE. ; saveMode EQU 0 ; the current mode setting ; savePage EQU saveMode+2 ; the current page setting ; saveBaseAddr EQU savePage+2 ; the current base address ; saveSQElPtr EQU saveBaseAddr+4 ; the SQ element pointer (for _SIntRemove). ; saveGammaPtr EQU saveSQElPtr+4 ; the pointer to the Gamma correction table ; GFlags EQU saveGammaPtr+4 ; flags word ; saveVidParms EQU GFlags+2 ; pointer to video configuration data ; saveID EQU saveVidParms+4 ; saved sense value ; saveHardBase EQU saveID+2 ; hardware base address ; saveMonSense EQU saveHardBase+4 ; reformatted sense line combo from videoOpen ; moreGFlags EQU saveMonSense+2 ; saveGammaPtrHead EQU moreGFlags+2 ; dCtlSize EQU saveGammaPtrHead+4 ; size of dCtlStorage ; Flags within GFlags word ; GrayFlag EQU 15 ; luminance mapped if GFlags(GrayFlag) = 1 ; IntDisFlag EQU 14 ; interrupts disabled if GFlags(IntFlag) =1 ; RAM512KFlag EQU 13 ; 512K vidRAM if GFlags(RAM512K) = 1 ; MonoFlag EQU 12 ; true if monochrome monitor ; Interlaced EQU 11 ; true if 12MHz NTSC mode ; DirectModeFlag EQU 10 ; true if direct mode (24 BPP) otherwise indexed ; BigScreen EQU 9 ; true if Kong or Portrait, false otherwise ; sRsrc32Bit EQU 8 ; true if the spID indicates it's a 32 bit sRsrc ; Flags within moreGFlags word ; UnderScanFlag EQU 15 ; ConvOnFlag EQU 14 ; PALFlag EQU 13 ; NationalFlag EQU 12 ;------------------------------------------------------------------- ; Video Driver Header ;------------------------------------------------------------------- VidDrvr DC.W $4C00 ; ctl,status,needsLock DC.W 0,0,0 ; not an ornament ; Entry point offset table DC.W VideoOpen-VidDrvr ; open routine DC.W VidDrvr-VidDrvr ; no prime DC.W VideoCtl-VidDrvr ; control DC.W VideoStatus-VidDrvr ; status DC.W VideoClose-VidDrvr ; close STRING Pascal VideoTitle DC.B '.Display_Video_Apple_MDC' STRING ASIS ALIGN ; make sure we're aligned DC.W CurJMFBDrvrVersion ; ; ; Here are the Elmer miscellaneous data and hardware parameters for the 4 different monitors. ; The interlaced monitor has 2 sets of parameters (no convolution and convolution). ; ; The miscellaneous data contains page size, rowbytes, and number of scanlines for all allowable ; modes of operation for a particular monitor. ; ; The six lines of hardware parameters data correspond to the initialization setup sequence ; summarized below. ; ; Line 1 - CLUT PBCR ; Line 2 - JMFB CSR, JMFB load divisor register, JMFB base register,JMFB row long words register ; Line 3 - Programable clock generator registers (interlaced convolved only) ; Line 4 - Stopwatch horizontal timing control parameters (see Stopwatch spec) ; Line 5 - Stopwatch vertical timing control parameters (see Stopwatch spec) ; Line 6 - Stopwatch composite timing control parameters (see Stopwatch spec) ; ; Note that the ROM can be built for the prototype VRAM or production VRAM. This ROM can now be ; used independent of whether the National or Endeavor clock generators are present. The implication ; of this is that the first JMFB register is setup in the data tables below for the National Part, ; (i.e. the PIXSEL1 bit = 1 for Kong and 0 for all other cases). In JMFBSetDepth, a check is made to ; see which clock part we're using and if it's Endeavor, PIXSEL1 will be set to 1. Otherwise the ; National setup would result in reseting Endeavor (to 10MHz) except for the Kong. ; Mode100Data Pages1024 DC.B OBMPages100B,TBMPages100B,FBMPages100B,EBMPages100B,TFBMPages100B Pages512 DC.B OBMPages100A,TBMPages100A,FBMPages100A,EBMPages100A,TFBMPages100A RowBites DC.W OBM100RB,TBM100RB,FBM100RB,EBM100RB,TFBM100RB Height DC.W defmBounds_B100 Mode100 OBM100Parms DC.W $00C0 IF ProtoVRAM THEN DC.W $2003,$00F8,defmBaseOffsetBS>>5,OBM100RB/4 ELSE DC.W $2002,$00F8,defmBaseOffsetBS>>5,OBM100RB/4 ENDIF DC.W $0003,$0000,$0090,$011E,$0016,$001E,$0012 DC.W $0003,$0000,$06CC,$004E,$0006,$0006 DC.W $0000,$014c TBM100Parms DC.W $00C8 IF ProtoVRAM THEN DC.W $2003,$00FC,defmBaseOffsetBS>>5,TBM100RB/4 ELSE DC.W $2002,$00FC,defmBaseOffsetBS>>5,TBM100RB/4 ENDIF DC.W $0003,$0000,$0090,$011E,$001A,$001E,$000E DC.W $0003,$0000,$06CC,$004E,$0006,$0006 DC.W $0000,$014c FBM100Parms DC.W $00D0 IF ProtoVRAM THEN DC.W $2003,$00FE,defmBaseOffsetBS>>5,FBM100RB/4 ELSE DC.W $2002,$00FE,defmBaseOffsetBS>>5,FBM100RB/4 ENDIF DC.W $0003,$0000,$0090,$011E,$001C,$001E,$000C DC.W $0003,$0000,$06CC,$004E,$0006,$0006 DC.W $0000,$014c EBM100Parms DC.W $00D8 IF ProtoVRAM THEN DC.W $2003,$00FF,defmBaseOffsetBS>>5,EBM100RB/4 ELSE DC.W $2002,$00FF,defmBaseOffsetBS>>5,EBM100RB/4 ENDIF DC.W $0003,$0000,$0090,$011E,$001D,$001E,$000B DC.W $0003,$0000,$06CC,$004E,$0006,$0006 DC.W $0000,$014c Mode57Data DC.B OBMPages57B,TBMPages57B,FBMPages57B,EBMPages57B,TFBMPages57B DC.B OBMPages57A,TBMPages57A,FBMPages57A,EBMPages57A,TFBMPages57A DC.W OBM57RB,TBM57RB,FBM57RB,EBM57RB,TFBM57RB DC.W defmBounds_B57 Mode57 OBM57Parms DC.W $00A0 IF ProtoVRAM THEN DC.W $0003,$00F0,defmBaseOffsetBS>>5,OBM57RB/4 ELSE DC.W $0002,$00F0,defmBaseOffsetBS>>5,OBM57RB/4 ENDIF DC.W $0003,$0000,$00A0,$013E,$0012,$0026,$0022 DC.W $0003,$0000,$06CC,$0054,$0006,$0006 DC.W $0000,$0178 TBM57Parms DC.W $00A8 IF ProtoVRAM THEN DC.W $0003,$00F8,defmBaseOffsetBS>>5,TBM57RB/4 ELSE DC.W $0002,$00F8,defmBaseOffsetBS>>5,TBM57RB/4 ENDIF DC.W $0003,$0000,$00A0,$013E,$001A,$0026,$001A DC.W $0003,$0000,$06CC,$0054,$0006,$0006 DC.W $0000,$0178 FBM57Parms DC.W $00B0 IF ProtoVRAM THEN DC.W $0003,$00FC,defmBaseOffsetBS>>5,FBM57RB/4 ELSE DC.W $0002,$00FC,defmBaseOffsetBS>>5,FBM57RB/4 ENDIF DC.W $0003,$0000,$00A0,$013E,$001E,$0026,$0016 DC.W $0003,$0000,$06CC,$0054,$0006,$0006 DC.W $0000,$0178 EBM57Parms DC.W $00B8 IF ProtoVRAM THEN DC.W $0003,$00FE,defmBaseOffsetBS>>5,EBM57RB/4 ELSE DC.W $0002,$00FE,defmBaseOffsetBS>>5,EBM57RB/4 ENDIF DC.W $0003,$0000,$00A0,$013E,$0020,$0026,$0014 DC.W $0003,$0000,$06CC,$0054,$0006,$0006 DC.W $0000,$0178 Mode30Data DC.B OBMPages30B,TBMPages30B,FBMPages30B,EBMPages30B,TFBMPages30B DC.B OBMPages30A,TBMPages30A,FBMPages30A,EBMPages30A,TFBMPages30A DC.W OBM30RB,TBM30RB,FBM30RB,EBM30RB,TFBM30RB DC.W defmBounds_B30 Mode30 OBM30Parms DC.W $0080 IF ProtoVRAM THEN DC.W $0083,$00E0,defmBaseOffset>>5,OBM30RB/4 ELSE DC.W $0082,$00E0,defmBaseOffset>>5,OBM30RB/4 ENDIF DC.W $0003,$0000,$013A,$027E,$0034,$003E,$0068 DC.W $0003,$0000,$03C0,$004E,$0006,$0006 DC.W $0004,$0320 TBM30Parms DC.W $0088 IF ProtoVRAM THEN DC.W $0083,$00F0,defmBaseOffset>>5,TBM30RB/4 ELSE DC.W $0082,$00F0,defmBaseOffset>>5,TBM30RB/4 ENDIF DC.W $0003,$0000,$012A,$027E,$0044,$003E,$0058 DC.W $0003,$0000,$03C0,$004E,$0006,$0006 DC.W $0004,$0320 FBM30Parms DC.W $0090 IF ProtoVRAM THEN DC.W $0083,$00F8,defmBaseOffset>>5,FBM30RB/4 ELSE DC.W $0082,$00F8,defmBaseOffset>>5,FBM30RB/4 ENDIF DC.W $0003,$0000,$0122,$027E,$004C,$003E,$0050 DC.W $0003,$0000,$03C0,$004E,$0006,$0006 DC.W $0004,$0320 EBM30Parms DC.W $0098 IF ProtoVRAM THEN DC.W $0083,$00FC,defmBaseOffset>>5,EBM30RB/4 ELSE DC.W $0082,$00FC,defmBaseOffset>>5,EBM30RB/4 ENDIF DC.W $0003,$0000,$011E,$027E,$0050,$003E,$004C DC.W $0003,$0000,$03C0,$004E,$0006,$0006 DC.W $0004,$0320 TFBM30Parms IF ProtoVRAM THEN DC.W $009A DC.W $0087,$00FF,(defmBaseOffset*3/4)>>5>>1,(TFBM30RB*3/4/4)>>1 ELSE DC.W $009A DC.W $0086,$00FF,(defmBaseOffset*3/4)>>5>>1,(TFBM30RB*3/4/4)>>1 ENDIF DC.W $0003,$0000,$0140,$027E,$0053,$003E,$0049 DC.W $0003,$0000,$03C0,$004E,$0006,$0006 DC.W $0004,$0320 Mode16Data DC.B OBMPages16B,TBMPages16B,FBMPages16B,EBMPages16B,TFBMPages16B DC.B OBMPages16A,TBMPages16A,FBMPages16A,EBMPages16A,TFBMPages16A DC.W OBM16RB,TBM16RB,FBM16RB,EBM16RB,TFBM16RB DC.W defmBounds_B16 Mode16 OBM16Parms DC.W $0080 IF ProtoVRAM THEN DC.W $0083,$00E0,defmBaseOffset>>5,OBM16RB/4 ELSE DC.W $0082,$00E0,defmBaseOffset>>5,OBM16RB/4 ENDIF DC.W $0003,$0000,$0100,$01FE,$024,$001E,$0038 DC.W $0003,$0000,$0300,$0026,$0006,$0002 DC.W $0004,$0260 TBM16Parms DC.W $0088 IF ProtoVRAM THEN DC.W $0083,$00F0,defmBaseOffset>>5,TBM16RB/4 ELSE DC.W $0082,$00F0,defmBaseOffset>>5,TBM16RB/4 ENDIF DC.W $0003,$0000,$0100,$01FE,$034,$001E,$0028 DC.W $0003,$0000,$0300,$0026,$0006,$0002 DC.W $0004,$0260 FBM16Parms DC.W $0090 IF ProtoVRAM THEN DC.W $0083,$00F8,defmBaseOffset>>5,FBM16RB/4 ELSE DC.W $0082,$00F8,defmBaseOffset>>5,FBM16RB/4 ENDIF DC.W $0003,$0000,$0100,$01FE,$03C,$001E,$0020 DC.W $0003,$0000,$0300,$0026,$0006,$0002 DC.W $0004,$0260 EBM16Parms DC.W $0098 IF ProtoVRAM THEN DC.W $0083,$00FC,defmBaseOffset>>5,EBM16RB/4 ELSE DC.W $0082,$00FC,defmBaseOffset>>5,EBM16RB/4 ENDIF DC.W $0003,$0000,$0100,$01FE,$040,$001E,$001C DC.W $0003,$0000,$0300,$0026,$0006,$0002 DC.W $0004,$0260 TFBM16Parms IF ProtoVRAM THEN DC.W $009A DC.W $0087,$00FF,(defmBaseOffset*3/4)>>5>>1,(TFBM16RB*3/4/4)>>1 ELSE DC.W $009A DC.W $0086,$00FF,(defmBaseOffset*3/4)>>5>>1,(TFBM16RB*3/4/4)>>1 ENDIF DC.W $0003,$0000,$0100,$01FE,$043,$001E,$0019 DC.W $0003,$0000,$0300,$0026,$0006,$0002 DC.W $0004,$0260 Mode14Data DC.B InvalPageCnt,InvalPageCnt,InvalPageCnt,InvalPageCnt,InvalPageCnt DC.B OBMPages14A,TBMPages14A,FBMPages14A,EBMPages14A,TFBMPages14A DC.W OBM14RB,TBM14RB,FBM14RB,EBM14RB,TFBM14RB DC.W defmBounds_B14 ; ; There is an interesting twist to all of the PAL timing parameters and it is in the vertical ; timing section. Since PAL doesn't have a half line at the top of one field and a half ; line at the bottom of the other field, but rather has a full line at the top of both ; fields and half lines at both bottoms, we have to adjust for this in Stopwatch. The way ; that this happens is a half line is taken of from active video and added to the back ; porch and then Stopwatch is reset as it normally is. Hey it works and it's late! ; Mode14 OBM14Parms DC.W $0080 IF ProtoVRAM THEN DC.W $8113,$00E0,defmBaseOffset12>>5,OBM14RB/4 ELSE DC.W $8112,$00E0,defmBaseOffset12>>5,OBM14RB/4 ENDIF DC.W $0003,$0000,$0160,$02FE,$0031,$0043,$0036 DC.W $0003,$0000,$023F,$0028,$0005,$0005 DC.W $005E,$0193 TBM14Parms DC.W $0088 IF ProtoVRAM THEN DC.W $8113,$00F0,defmBaseOffset12>>5,TBM14RB/4 ELSE DC.W $8112,$00F0,defmBaseOffset12>>5,TBM14RB/4 ENDIF DC.W $0003,$0000,$0150,$02FE,$0041,$0043,$0026 DC.W $0003,$0000,$023F,$0028,$0005,$0005 DC.W $005E,$0193 FBM14Parms DC.W $0090 IF ProtoVRAM THEN DC.W $8113,$00F8,defmBaseOffset12>>5,FBM14RB/4 ELSE DC.W $8112,$00F8,defmBaseOffset12>>5,FBM14RB/4 ENDIF DC.W $0003,$0000,$0148,$02FE,$0049,$0043,$001E DC.W $0003,$0000,$023F,$0028,$0005,$0005 DC.W $005E,$0193 EBM14Parms DC.W $0098 IF ProtoVRAM THEN DC.W $8113,$00FC,defmBaseOffset12>>5,EBM14RB/4 ELSE DC.W $8112,$00FC,defmBaseOffset12>>5,EBM14RB/4 ENDIF DC.W $0003,$0000,$0144,$02FE,$004D,$0043,$001A DC.W $0003,$0000,$023F,$0028,$0005,$0005 DC.W $005E,$0193 Mode14CData DC.B OBMPages14CB,TBMPages14CB,FBMPages14CB,EBMPages14CB,TFBMPages14CB DC.B InvalPageCnt,InvalPageCnt,InvalPageCnt,InvalPageCnt,InvalPageCnt DC.W OBM14CRB,TBM14CRB,FBM14CRB,EBM14CRB,TFBM14CRB DC.W defmBounds_B14 Mode14C OBM14CParms DC.W $00C1 IF ProtoVRAM THEN DC.W $8133,$00F8,(defmbaseOffset12-convBOfix)>>5,OBM14CRB/4 ELSE DC.W $8132,$00F8,(defmbaseOffset12-convBOfix)>>5,OBM14CRB/4 ENDIF DC.W $0000,$0000,$0000 DC.B $0D,$09,$01,$00,$06,$04,$00,$01 DC.B $01,$01,$0D,$06,$00,$01,$00,$00 DC.W $0003,$0000,$0160,$02FE,$0031,$0043,$0036 DC.W $0003,$0000,$023F,$0028,$0005,$0005 DC.W $005E,$0193 TBM14CParms DC.W $00C9 IF ProtoVRAM THEN DC.W $8133,$00FC,(defmbaseOffset12-convBOfix)>>5,TBM14CRB/4 ELSE DC.W $8132,$00FC,(defmbaseOffset12-convBOfix)>>5,TBM14CRB/4 ENDIF DC.W $0000,$0000,$0000 DC.B $0D,$09,$01,$00,$06,$04,$00,$01 DC.B $01,$01,$0D,$06,$00,$01,$00,$00 DC.W $0003,$0000,$0150,$02FE,$0041,$0043,$0026 DC.W $0003,$0000,$023F,$0028,$0005,$0005 DC.W $005E,$0193 FBM14CParms DC.W $00D1 IF ProtoVRAM THEN DC.W $8133,$00FE,(defmbaseOffset12-convBOfix)>>5,FBM14CRB/4 ELSE DC.W $8132,$00FE,(defmbaseOffset12-convBOfix)>>5,FBM14CRB/4 ENDIF DC.W $0000,$0000,$0000 DC.B $0D,$09,$01,$00,$06,$04,$00,$01 DC.B $01,$01,$0D,$06,$00,$01,$00,$00 DC.W $0003,$0000,$0148,$02FE,$0049,$0043,$001E DC.W $0003,$0000,$023F,$0028,$0005,$0005 DC.W $005E,$0193 EBM14CParms DC.W $00D9 IF ProtoVRAM THEN DC.W $8133,$00FF,(defmbaseOffset12-convBOfix)>>5,EBM14CRB/4 ELSE DC.W $8132,$00FF,(defmbaseOffset12-convBOfix)>>5,EBM14CRB/4 ENDIF DC.W $0000,$0000,$0000 DC.B $0D,$09,$01,$00,$06,$04,$00,$01 DC.B $01,$01,$0D,$06,$00,$01,$00,$00 DC.W $0003,$0000,$0144,$02FE,$004D,$0043,$001A DC.W $0003,$0000,$023F,$0028,$0005,$0005 DC.W $005E,$0193 ; ; 24 bpp is not an allowable mode for overscan PAL, so no table here! ; Mode14uData DC.B InvalPageCnt,InvalPageCnt,InvalPageCnt,InvalPageCnt,InvalPageCnt DC.B OBMPages14Au,TBMPages14Au,FBMPages14Au,EBMPages14Au,TFBMPages14Au DC.W OBM14uRB,TBM14uRB,FBM14uRB,EBM14uRB,TFBM14uRB DC.W defmBounds_B14u Mode14u OBM14uParms DC.W $0080 IF ProtoVRAM THEN DC.W $8113,$00E0,defmBaseOffset12>>5,OBM14uRB/4 ELSE DC.W $8112,$00E0,defmBaseOffset12>>5,OBM14uRB/4 ENDIF DC.W $0003,$0000,$0120,$027e,$0071,$0043,$0076 DC.W $0003,$0000,$020f,$0058,$0005,$0005 DC.W $005E,$0193 TBM14uParms DC.W $0088 IF ProtoVRAM THEN DC.W $8113,$00F0,defmBaseOffset12>>5,TBM14uRB/4 ELSE DC.W $8112,$00F0,defmBaseOffset12>>5,TBM14uRB/4 ENDIF DC.W $0003,$0000,$0110,$027e,$0081,$0043,$0066 DC.W $0003,$0000,$020f,$0058,$0005,$0005 DC.W $005E,$0193 FBM14uParms DC.W $0090 IF ProtoVRAM THEN DC.W $8113,$00F8,defmBaseOffset12>>5,FBM14uRB/4 ELSE DC.W $8112,$00F8,defmBaseOffset12>>5,FBM14uRB/4 ENDIF DC.W $0003,$0000,$0108,$027e,$0089,$0043,$005e DC.W $0003,$0000,$020f,$0058,$0005,$0005 DC.W $005E,$0193 EBM14uParms DC.W $0098 IF ProtoVRAM THEN DC.W $8113,$00FC,defmBaseOffset1212>>5,EBM14uRB/4 ELSE DC.W $8112,$00FC,defmBaseOffset12>>5,EBM14uRB/4 ENDIF DC.W $0003,$0000,$0104,$027e,$008d,$0043,$005a DC.W $0003,$0000,$020f,$0058,$0005,$0005 DC.W $005E,$0193 Mode14CuData DC.B OBMPages14CB,TBMPages14CB,FBMPages14CB,EBMPages14CB,TFBMPages14Bu DC.B InvalPageCnt,InvalPageCnt,InvalPageCnt,InvalPageCnt,InvalPageCnt DC.W OBM14CRB,TBM14CRB,FBM14CRB,EBM14CRB,TFBM14uRB DC.W defmBounds_B14u Mode14Cu OBM14CuParms DC.W $00C1 IF ProtoVRAM THEN DC.W $8133,$00F8,(defmbaseOffset12-convBOfix)>>5,OBM14CRB/4 ELSE DC.W $8132,$00F8,(defmbaseOffset12-convBOfix)>>5,OBM14CRB/4 ENDIF DC.W $0000,$0000,$0000 DC.B $0D,$09,$01,$00,$06,$04,$00,$01 DC.B $01,$01,$0D,$06,$00,$01,$00,$00 DC.W $0003,$0000,$0120,$027e,$0071,$0043,$0076 DC.W $0003,$0000,$020f,$0058,$0005,$0005 DC.W $005E,$0193 TBM14CuParms DC.W $00C9 IF ProtoVRAM THEN DC.W $8133,$00FC,(defmbaseOffset12-convBOfix)>>5,TBM14CRB/4 ELSE DC.W $8132,$00FC,(defmbaseOffset12-convBOfix)>>5,TBM14CRB/4 ENDIF DC.W $0000,$0000,$0000 DC.B $0D,$09,$01,$00,$06,$04,$00,$01 DC.B $01,$01,$0D,$06,$00,$01,$00,$00 DC.W $0003,$0000,$0110,$027e,$0081,$0043,$0066 DC.W $0003,$0000,$020f,$0058,$0005,$0005 DC.W $005E,$0193 FBM14CuParms DC.W $00D1 IF ProtoVRAM THEN DC.W $8133,$00FE,(defmbaseOffset12-convBOfix)>>5,FBM14CRB/4 ELSE DC.W $8132,$00FE,(defmbaseOffset12-convBOfix)>>5,FBM14CRB/4 ENDIF DC.W $0000,$0000,$0000 DC.B $0D,$09,$01,$00,$06,$04,$00,$01 DC.B $01,$01,$0D,$06,$00,$01,$00,$00 DC.W $0003,$0000,$0108,$027e,$0089,$0043,$005e DC.W $0003,$0000,$020f,$0058,$0005,$0005 DC.W $005E,$0193 EBM14CuParms DC.W $00D9 IF ProtoVRAM THEN DC.W $8133,$00FF,(defmbaseOffset12-convBOfix)>>5,EBM14CRB/4 ELSE DC.W $8132,$00FF,(defmbaseOffset12-convBOfix)>>5,EBM14CRB/4 ENDIF DC.W $0000,$0000,$0000 DC.B $0D,$09,$01,$00,$06,$04,$00,$01 DC.B $01,$01,$0D,$06,$00,$01,$00,$00 DC.W $0003,$0000,$0104,$027e,$008d,$0043,$005a DC.W $0003,$0000,$020f,$0058,$0005,$0005 DC.W $005E,$0193 ; ; Note that the 24 BPP convolution parameters are identical to the 24 BPP no convolution parameters ; since convolution cannot be performed in 24 BPP mode. The no convolution parameters will be used ; when only one bank of vRAM is present on the card and the convolution parameters will be used ; when the second bank is present. ; TFBM14CuParms DC.W $009A IF ProtoVRAM THEN DC.W $8117,$00FF,$0000,(TFBM14uRB*3/4/4)>>1 ELSE DC.W $8116,$00FF,$0000,(TFBM14uRB*3/4/4)>>1 ENDIF DC.W $0000,$0000,$0000 DC.B $0D,$09,$01,$00,$06,$04,$00,$01 DC.B $01,$03,$0D,$06,$00,$01,$00,$00 DC.W $0003,$0000,$0101,$027e,$0090,$0043,$0057 DC.W $0003,$0000,$020f,$0058,$0005,$0005 DC.W $005E,$0193 Mode12Data DC.B OBMPages12B,TBMPages12B,FBMPages12B,EBMPages12B,TFBMPages12B DC.B OBMPages12A,TBMPages12A,FBMPages12A,EBMPages12A,TFBMPages12A DC.W OBM12CRB,TBM12CRB,FBM12CRB,EBM12CRB,TFBM12CRB DC.W defmBounds_B12 Mode12 ; There is a bug with the 1 BPP ntsc parameters since we can't meet the horizontal timing requirements!! OBM12Parms DC.W $0080 IF ProtoVRAM THEN DC.W $8113,$00E0,defmbaseOffset12>>5,OBM12CRB/4 ELSE DC.W $8112,$00E0,defmbaseOffset12>>5,OBM12CRB/4 ENDIF DC.W $0003,$0000,$0136,$027E,$0012,$003A,$003a DC.W $0003,$0000,$01E0,$0021,$0006,$0006 DC.W $006E,$014a TBM12Parms DC.W $0088 IF ProtoVRAM THEN DC.W $8113,$00F0,defmbaseOffset12>>5,TBM12CRB/4 ELSE DC.W $8112,$00F0,defmbaseOffset12>>5,TBM12CRB/4 ENDIF DC.W $0003,$0000,$0126,$027E,$0022,$003A,$002a DC.W $0003,$0000,$01E0,$0021,$0006,$0006 DC.W $006E,$014a FBM12Parms DC.W $0090 IF ProtoVRAM THEN DC.W $8113,$00F8,defmbaseOffset12>>5,FBM12CRB/4 ELSE DC.W $8112,$00F8,defmbaseOffset12>>5,FBM12CRB/4 ENDIF DC.W $0003,$0000,$011e,$027E,$002a,$003A,$0022 DC.W $0003,$0000,$01E0,$0021,$0006,$0006 DC.W $006E,$014a EBM12Parms DC.W $0098 IF ProtoVRAM THEN DC.W $8113,$00FC,defmbaseOffset12>>5,EBM12CRB/4 ELSE DC.W $8112,$00FC,defmbaseOffset12>>5,EBM12CRB/4 ENDIF DC.W $0003,$0000,$011a,$027E,$002e,$003A,$001e DC.W $0003,$0000,$01E0,$0021,$0006,$0006 DC.W $006E,$014a Mode12CData DC.B OBMPages12CB,TBMPages12CB,FBMPages12CB,EBMPages12CB,TFBMPages12B DC.B OBMPages12CA,TBMPages12CA,FBMPages12CA,EBMPages12CA,TFBMPages12CA DC.W OBM12CRB,TBM12CRB,FBM12CRB,EBM12CRB,TFBM12CRB DC.W defmBounds_B12C Mode12C OBM12CParms DC.W $00C1 IF ProtoVRAM THEN DC.W $8133,$00F8,(defmbaseOffset12-convBOfix)>>5,OBM12CRB/4 ELSE DC.W $8132,$00F8,(defmbaseOffset12-convBOfix)>>5,OBM12CRB/4 ENDIF BeginEndeavor DC.W $006C,$00B0,$0000 EndEndeavor Natl DC.B $0c,$01,$02,$00,$07,$03,$00,$00 DC.B $00,$02,$0D,$06,$00,$01,$00,$00 EndNatl DC.W $0003,$0000,$0136,$027E,$0012,$003A,$003A DC.W $0003,$0000,$01E0,$0021,$0006,$0006 DC.W $006E,$014a TBM12CParms DC.W $00C9 IF ProtoVRAM THEN DC.W $8133,$00FC,(defmbaseOffset12-convBOfix)>>5,TBM12CRB/4 ELSE DC.W $8132,$00FC,(defmbaseOffset12-convBOfix)>>5,TBM12CRB/4 ENDIF DC.W $006C,$00B0,$0000 DC.B $0c,$01,$02,$00,$07,$03,$00,$00 DC.B $00,$02,$0D,$06,$00,$01,$00,$00 DC.W $0003,$0000,$0126,$027E,$0022,$003A,$002A DC.W $0003,$0000,$01E0,$0021,$0006,$0006 DC.W $006E,$014a FBM12CParms DC.W $00D1 IF ProtoVRAM THEN DC.W $8133,$00FE,(defmbaseOffset12-convBOfix)>>5,FBM12CRB/4 ELSE DC.W $8132,$00FE,(defmbaseOffset12-convBOfix)>>5,FBM12CRB/4 ENDIF DC.W $006C,$00B0,$0000 DC.B $0c,$01,$02,$00,$07,$03,$00,$00 DC.B $00,$02,$0D,$06,$00,$01,$00,$00 DC.W $0003,$0000,$011e,$027E,$002A,$003A,$0022 DC.W $0003,$0000,$01E0,$0021,$0006,$0006 DC.W $006E,$014a EBM12CParms DC.W $00D9 IF ProtoVRAM THEN DC.W $8133,$00FF,(defmbaseOffset12-convBOfix)>>5,EBM12CRB/4 ELSE DC.W $8132,$00FF,(defmbaseOffset12-convBOfix)>>5,EBM12CRB/4 ENDIF DC.W $006C,$00B0,$0000 DC.B $0c,$01,$02,$00,$07,$03,$00,$00 DC.B $00,$02,$0D,$06,$00,$01,$00,$00 DC.W $0003,$0000,$011a,$027E,$002E,$003A,$001E DC.W $0003,$0000,$01E0,$0021,$0006,$0006 DC.W $006E,$014a ; ; Note that the 24 BPP convolution parameters are identical to the 24 BPP no convolution parameters ; since convolution cannot be performed in 24 BPP mode. The no convolution parameters will be used ; when only one bank of vRAM is present on the card and the convolution parameters will be used ; when the second bank is present. ; TFBM12CParms DC.W $009A IF ProtoVRAM THEN DC.W $8117,$00FF,$0000,(TFBM12RB*3/4/4)>>1 ELSE DC.W $8116,$00FF,$0000,(TFBM12RB*3/4/4)>>1 ENDIF DC.W $001B,$00B0,$0000 DC.B $0c,$01,$02,$00,$07,$03,$00,$00 DC.B $00,$04,$0D,$06,$00,$01,$00,$00 DC.W $0003,$0000,$011d,$027E,$002B,$003A,$0021 DC.W $0003,$0000,$01E0,$0021,$0006,$0006 DC.W $006E,$014a Mode12uData DC.B OBMPages12B,TBMPages12B,FBMPages12B,EBMPages12B,TFBMPages12B DC.B OBMPages12A,TBMPages12A,FBMPages12A,EBMPages12A,TFBMPages12A DC.W OBM12CRB,TBM12CRB,FBM12CRB,EBM12CRB,TFBM12CRB DC.W defmBounds_B12u Mode12u OBM12uParms DC.W $0080 IF ProtoVRAM THEN DC.W $8113,$00E0,defmbaseOffset12>>5,OBM12CRB/4 ELSE DC.W $8112,$00E0,defmbaseOffset12>>5,OBM12CRB/4 ENDIF ; Based on lab measurements the delta value to fp/bp is $8 rather than $20. DC.W $0003,$0000,$00f4,$01fe,$0054,$003A,$0078 DC.W $0003,$0000,$01B0,$0051,$0006,$0006 DC.W $006E,$014A TBM12uParms DC.W $0088 IF ProtoVRAM THEN DC.W $8113,$00F0,defmbaseOffset12>>5,TBM12CRB/4 ELSE DC.W $8112,$00F0,defmbaseOffset12>>5,TBM12CRB/4 ENDIF ; Based on lab measurements the delta value to fp/bp is $8 rather than $20. DC.W $0003,$0000,$00e4,$01fe,$0064,$003A,$0068 DC.W $0003,$0000,$01B0,$0051,$0006,$0006 DC.W $006E,$014A FBM12uParms DC.W $0090 IF ProtoVRAM THEN DC.W $8113,$00F8,defmbaseOffset12>>5,FBM12CRB/4 ELSE DC.W $8112,$00F8,defmbaseOffset12>>5,FBM12CRB/4 ENDIF ; Based on lab measurements the delta value to fp/bp is $8 rather than $20. DC.W $0003,$0000,$00dc,$01fe,$006c,$003A,$0060 DC.W $0003,$0000,$01B0,$0051,$0006,$0006 DC.W $006E,$014A EBM12uParms DC.W $0098 IF ProtoVRAM THEN DC.W $8113,$00FC,defmbaseOffset12>>5,EBM12CRB/4 ELSE DC.W $8112,$00FC,defmbaseOffset12>>5,EBM12CRB/4 ENDIF ; Based on lab measurements the delta value to fp/bp is $8 rather than $20. DC.W $0003,$0000,$00d8,$01fe,$0070,$003A,$005c DC.W $0003,$0000,$01B0,$0051,$0006,$0006 DC.W $006E,$014A Mode12CuData DC.B OBMPages12CB,TBMPages12CB,FBMPages12CB,EBMPages12CB,TFBMPages12B DC.B OBMPages12CA,TBMPages12CA,FBMPages12CA,EBMPages12CA,TFBMPages12CA DC.W OBM12CRB,TBM12CRB,FBM12CRB,EBM12CRB,TFBM12CRB DC.W defmBounds_B12u Mode12Cu OBM12CuParms DC.W $00C1 IF ProtoVRAM THEN DC.W $8133,$00F8,(defmbaseOffset12-convBOfix)>>5,OBM12CRB/4 ELSE DC.W $8132,$00F8,(defmbaseOffset12-convBOfix)>>5,OBM12CRB/4 ENDIF DC.W $006C,$00B0,$0000 DC.B $0c,$01,$02,$00,$07,$03,$00,$00 DC.B $00,$02,$0D,$06,$00,$01,$00,$00 ; Based on lab measurements the delta value to fp/bp is $8 rather than $20. DC.W $0003,$0000,$00f4,$01fe,$0054,$003A,$0078 DC.W $0003,$0000,$01B0,$0051,$0006,$0006 DC.W $006E,$014A TBM12CuParms DC.W $00C9 IF ProtoVRAM THEN DC.W $8133,$00FC,(defmbaseOffset12-convBOfix)>>5,TBM12CRB/4 ELSE DC.W $8132,$00FC,(defmbaseOffset12-convBOfix)>>5,TBM12CRB/4 ENDIF DC.W $006C,$00B0,$0000 DC.B $0c,$01,$02,$00,$07,$03,$00,$00 DC.B $00,$02,$0D,$06,$00,$01,$00,$00 ; Based on lab measurements the delta value to fp/bp is $8 rather than $20. DC.W $0003,$0000,$00e4,$01fe,$0064,$003A,$0068 DC.W $0003,$0000,$01B0,$0051,$0006,$0006 DC.W $006E,$014A FBM12CuParms DC.W $00D1 IF ProtoVRAM THEN DC.W $8133,$00FE,(defmbaseOffset12-convBOfix)>>5,FBM12CRB/4 ELSE DC.W $8132,$00FE,(defmbaseOffset12-convBOfix)>>5,FBM12CRB/4 ENDIF DC.W $006C,$00B0,$0000 DC.B $0c,$01,$02,$00,$07,$03,$00,$00 DC.B $00,$02,$0D,$06,$00,$01,$00,$00 ; Based on lab measurements the delta value to fp/bp is $8 rather than $20. DC.W $0003,$0000,$00dc,$01fe,$006c,$003A,$0060 DC.W $0003,$0000,$01B0,$0051,$0006,$0006 DC.W $006E,$014A EBM12CuParms DC.W $00D9 IF ProtoVRAM THEN DC.W $8133,$00FF,(defmbaseOffset12-convBOfix)>>5,EBM12CRB/4 ELSE DC.W $8132,$00FF,(defmbaseOffset12-convBOfix)>>5,EBM12CRB/4 ENDIF DC.W $006C,$00B0,$0000 DC.B $0c,$01,$02,$00,$07,$03,$00,$00 DC.B $00,$02,$0D,$06,$00,$01,$00,$00 ; Based on lab measurements the delta value to fp/bp is $8 rather than $20. DC.W $0003,$0000,$00d8,$01fe,$0070,$003A,$005c DC.W $0003,$0000,$01B0,$0051,$0006,$0006 DC.W $006E,$014A ; ; Note that the 24 BPP convolution parameters are identical to the 24 BPP no convolution parameters ; since convolution cannot be performed in 24 BPP mode. The no convolution parameters will be used ; when only one bank of vRAM is present on the card and the convolution parameters will be used ; when the second bank is present. ; TFBM12CuParms DC.W $009A IF ProtoVRAM THEN DC.W $8117,$00FF,$0000,(TFBM12RB*3/4/4)>>1 ELSE DC.W $8116,$00FF,$0000,(TFBM12RB*3/4/4)>>1 ENDIF DC.W $001B,$00B0,$0000 DC.B $0c,$01,$02,$00,$07,$03,$00,$00 DC.B $00,$04,$0D,$06,$00,$01,$00,$00 ; Based on lab measurements the delta value to fp/bp is $8 rather than $20. DC.W $0003,$0000,$00d5,$01fe,$0073,$003A,$0059 DC.W $0003,$0000,$01B0,$0051,$0006,$0006 DC.W $006E,$014A ; ; Here are the offsets to each of the various data fields. The size of all miscellaneous data blocks ; is the same. ; D_Pages1024 EQU Pages1024-Mode100 D_Pages512 EQU Pages512-Mode100 D_RowBytes EQU RowBites-Mode100 D_Height EQU Height-Mode100 D_OBP EQU OBM100Parms-Mode100 D_TBP EQU TBM100Parms-Mode100 D_FBP EQU FBM100Parms-Mode100 D_EBP EQU EBM100Parms-Mode100 D_TFBP EQU TFBM30Parms-Mode30 ; Use Mode30 here since Mode100 doesn't do 24 BPP D_ClockParams EQU EndNatl-BeginEndeavor D_Endeavor EQU EndEndeavor-BeginEndeavor D_Natl EQU EndNatl-Natl ; ; CountTbl is the number of entries to change in each mode, set up to be indexed ; via the modeID. ; CountTbl DC.B $01,$03,$0F,$FF,$FF DC.B 'Software by Casey King, Hardware by James Lundblad and Mohammed Sriti' ALIGN 2 ; correct odd alignment ******************************************************************* * * VideoOpen allocates private storage for the device in the DCE and locks * it down for perpetuity. Also, install the interrupt handler and enable * the interrupts. * * VideoOpen is broken up into 7 main steps: * * 1. Allocate private storage and point to it with dCtlStorage from DCE. * 2. Form 32 bit base address and store in privates. * 3. Determine whether it's a 24 bit or 32 bit sRsrc and store in privates. * 4. Size VRAM and store in privates. * 5. Read sense lines from hw and ... * a. Save a ptr to the appropriate hw setup params. * b. Calc and save the BigScreen, GrayFlag, MonoFlag, Interlaced, PALFlag, and underScan flags. * c. If connected to interlaced monitor, determine whether to ntsc or pal and to oscan or uscan * 6. Get and install the interrupt handler. * 7. Load the correct gamma table as a f(monitor). * * Called by: * * Normally only Mac OS and A/UX. * * Traps and Utilities called: * * _ResrvMem, _NewHandle, _HLock, _StripAddress, _SwapMMUMode, _sReadPRAMRec, * EnableVGuts * * Register usage: * * Input: * A0 = param block pointer * A1 = DCE pointer * * Output * D0 = error code. * * Locally used * D0 = scratch * D1 = scratch * D3 = saves the spID from the AuxDCE * * A0 = points to the cards base address * = later points to the hw setup params * = later as a ptr to a parameter block * A3 = pointer to private storage * * Miscellaneous: * * None. * ******************************************************************* WITH VDPageInfo,SlotIntQElement,SEBlock,spBlock VideoOpen ; ; Allocate private storage (since block is CLEAR, GFlags are zeroed) and get ; a pointer to it in A3 ; MOVEQ #dCtlSize,D0 ; get size of parameters _ResrvMem ,SYS ; make room as low as possible MOVEQ #dCtlSize,D0 ; get size of parameters _NewHandle ,SYS,CLEAR ; get some memory for private storage BNE OpError ; => return an error in open MOVE.L A0,dCtlStorage(A1) ; save returned handle in DCE _HLock ; and lock it down MOVE.L (A0),D0 ; get a pointer to it _StripAddress ; strip it since we'll use it in 32 bit addressing MOVE.L D0,A3 ; and put it in A3 ; ; form the 32 bit base address in A0 and save in saveHardBase(A3). We ; cannot be assured that dctlDevBase(A1) contains the correct 32 bit ; address since a 24 bit sRsrc may be the active one if the new version of ; the slot manager is not present. ; MOVE.L #$F0000000,D1 MOVE.B dCtlSlot(A1),D0 BFINS D0,D1{4:4} MOVE.L D1,A0 MOVE.L A0,saveHardBase(A3) ; save this in privates for the interrupt handler ; ; determine if we're using a National or Endeavor Clock ; MOVE.L A0,-(SP) ; save A0 as it is used later SUBA #spBlockSize,SP ; get slot param block MOVE.L SP,A0 ; save pointer to it in A0 MOVE.B D0,spSlot(A0) ; put slot in slot param block SUBA #sizesPRAMRec,SP ; get PRAM record MOVE.L SP,spResult(A0) ; set up a pointer to result _SReadPRAMRec CMP.B #0,SavedClockType(SP) ; check for Endeavor BEQ.S EndClkCheck BSET #NationalFlag,moreGFlags(A3) EndClkCheck ADDA #sizesPRAMRec+spBlockSize,SP ; flush param blocks MOVE.L (SP)+,A0 ; restore A0 ; determine if the installed sResource is 24 bit (0) or 32 bit (1) from the AuxDCE record ; - Refer to OMD software ERS for definition of all spID bits ; MOVE.B dCtlSlotID(A1),D3 ; get the current sResource ID BTST #fSRsrc24Bit,D3 ; check for b4 state (24 bit=1, 32 bit=0) BNE.S @sizeVRAM BSET #sRsrc32bit,GFlags(A3) ; set the 32bit sRsrc bit in GFlags ; ; determine the memory size of the active sRsrc from the AuxDCE spID and set private storage bit ; @sizeVRAM BTST #fSRsrcXMemBit,D3 BNE.S @monSense BSET #RAM512KFlag,GFlags(A3) ; and set 512K vRAM flag (this is why we strip address) ; ; read the monitor sense lines to determine the configuration. Use this info ; to pick up a pointer to the parameter table for this hardware mode and ; save this pointer off in private storage. Since we had to get through ; primary init, the monitor sense line must be valid. The monitor sense ; combination is read from the JMFB CSR which is located at zero offset ; from the JMFB control space. Note that we can't use the sRsrc ID from ; the AuxDCE here because not all bits are saved in the spID. To support ; the RGB Kong and Portrait in the future we must go back out to the ; card and get the whole sense! ; ; Note that we're providing minimal functionality with the Sarnoff breakout ; box. We use the extended sense scheme to support both the Sarnoff NTSC mode ; and the Sarnoff PAL mode. At this time there is no support for the monitor ; connected to the auxillary DB15 connector on Sarnoff. ; @monSense MOVEQ #true32b,D0 ; change to 32 bit addressing to get _SwapMMUMode ; sense lines MOVE D0,-(SP) ; save the past mode on the stack MOVE.L #JMFB,D0 ; get offset in register BFEXTU (A0,D0.L){20:3},D1 ; get the state of the sense lines CMP.B #NoSense,D1 ; check for no sense BNE.S @DoNext ; if we get a valid sense, go on MOVE.L D0,D1 ; setup for GetXtndSense (so we use same interface as pinit) MOVE.L A1,-(SP) ; setup for GetXtndSense (save A1) MOVE.L A0,A1 ; setup for GetXtndSense (so we use same interface as pinit) BSR GetXtndSense ; go see if we see an xtended sense MOVE.L (SP)+,A1 ; restore A1 CMP.B #Sarnoff,D0 ; we only understand sarnoff If ForROM Then Bne.s @NoConnect ; if not Sarnoff (NTSC), then no connect Else BNE.S @TryPAL ; if not Sarnoff (NTSC), then try for PAL EndIf MOVE.B #_NTSC_,D1 ; force sarnoff to ntsc timing for now BRA.S @SwapBack ; we have a current mode so go on If Not ForROM Then @TryPAL CMP.B #PAL,D0 ; check for PAL xtnded sense BNE.S @TryPAL2 MOVE.B #rPAL,D1 BRA.S @SwapBack @TryPAL2 CMP.b #PALmonitor,D0 ; check for PAL monitor xtnded sense BNE.S @NoConnect ; if not found then do no connect MOVE.B #rPAL,D1 BRA.S @SwapBack EndIf @NoConnect MOVE.B #0,D1 ; no valid xtnd sense so do no connect BRA.S @SwapBack ; @DoNext CMP.B #RGBKong,D1 ; check to see if its an RGBKong BNE.S @SwapBack ; if not skip and go on MOVE.B #rRGBKong,D1 ; if it is, reformat to maintain convention ; All done with 32 bit addressing needs so go back into 24 bit addressing. @SwapBack MOVE (SP)+,D0 ; restore old addr mode into D0 _SwapMMUMode BTST #fSRsrcBigScrnBit,D1 ; check for Kong or Portrait monitor (bit 0 = 1) BEQ.S @colorMon ; if its other (0), then branch BSET #BigScreen,GFlags(A3) ; while we are here not that it's a big screen! BCLR #fSRsrcRGBBit,D1 ; b2 is not significant in Portrait or Kong sRsrcs so get rid of it BNE.S @colorMon ; remember BCLR tests before CLR, so check for color BSET #GrayFlag,GFlags(A3) BSET #MonoFlag,GFlags(A3) @colorMon MOVE.L D1,D0 ; use D0 for the jump tbl, since we want to keep D1 intact for interlaced selection. CMP.W #7,D0 ; range check the monitor id BHI OpError ; Error, out of bounds MOVE.W VOpenJumpTbl(PC,D0.W*2),D0 ; Get the relative offset to the routine JMP VOpenJumpTbl(PC,D0.W) ; GOTO the proper routine VOpenJumpTbl DC.W VOPAL-VOpenJumpTbl ; $00 => PAL monitor (use common code) DC.W VOPortrait-VOpenJumpTbl ; $01 => B/W Portrait (no difference between RGB and BW) DC.W VORubik-VOpenJumpTbl ; $02 => Rubik monitor DC.W VOKong-VOpenJumpTbl ; $03 => B/W Kong (no difference between RGB and BW) DC.W VONTSC-VOpenJumpTbl ; $04 => NTSC monitor (use common code) DC.W VOPortrait-VOpenJumpTbl ; $05 => RGB Portrait (no difference between RGB and BW) DC.W VOStandard-VOpenJumpTbl ; $06 => Standard monitor DC.W VOKong-VOpenJumpTbl ; $07 => RGB Kong (no difference between RGB and BW) VOStandard LEA Mode30,A0 ; else it better be standard size monitor BRA SaveIt ; branch to the setup code VORubik LEA Mode16,A0 ; point to the parameters BRA SaveIt ; branch to the setup code VOKong LEA Mode100,A0 ; point to the parameters BRA SaveIt ; branch to the setup code VOPortrait LEA Mode57,A0 ; point to the parameters BRA SaveIt ; branch to the setup code VOPAL BSET #PALFlag,moreGFlags(A3) ; set PALFlag for PAL BRA.S VOInterlaced ; go to common code VONTSC BCLR #PALFlag,moreGFlags(A3) ; set PALFlag for NTSC (not PAL) VOInterlaced BSET #Interlaced,GFlags(A3) ; set 12MHz mode flag ; ; if we're doing ntsc, check the underscan/overscan bit in the sRsrc ID (again from AuxDCE) ; BTST #fSRsrcOscanBit,D3 ; test the state of the underscan (0) / overscan (1) flag BNE.S testRAMFlag BSET #underScanFlag,moreGFlags(A3) ; it was 0 so set it for underscan testRAMFlag BTST #RAM512KFlag,GFlags(A3) ; test to see if we have one bank (no convol) or two (convol) BEQ.S useNTSCcon ; if two banks then its convolution capable so use Mode12C BTST #underScanFlag,moreGFlags(A3) ; test to see if we're underscan or overscan BNE.S useNTSCu ; if 1 then underscan so branch CMP.B #_NTSC_,D1 BEQ.S @useNTSC LEA Mode14,A0 BRA.S SaveIt @useNTSC LEA Mode12,A0 ; otherwise point to the overscan interlace flicker ones BRA.S SaveIt useNTSCu CMP.B #_NTSC_,D1 BEQ.S @useNTSC LEA Mode14u,A0 BRA.S SaveIt @useNTSC LEA Mode12u,A0 ; point to the underscan interlace flicker params BRA.S SaveIt useNTSCcon BSET #convOnFlag,moreGFlags(A3) ; set if we're in a convolution mode BTST #underScanFlag,moreGFlags(A3) ; test to see if we're underscan or overscan BNE.S useConvUscan ; if 1 then underscan so branch CMP.B #_NTSC_,D1 BEQ.S @useNTSC LEA Mode14C,A0 BRA.S SaveIt @useNTSC LEA Mode12C,A0 ; must have both vRAM banks and be overscanning so use Oscan convolution BRA.S SaveIt useConvUscan CMP.B #_NTSC_,D1 BEQ.S @useNTSC LEA Mode14Cu,A0 BRA.S SaveIt @useNTSC LEA Mode12Cu,A0 ; we have 2 banks and doing underscan so use Uscan convolution SaveIt MOVE.L A0,saveVidParms(A3) ; and save it for later MOVE.W D1,saveMonSense(A3) ; also save the LS 3 bits of reformatted monitor value ; ; clear a couple of bits in D3 since it will be used to get the right gamma table in a second ; BCLR #fSRsrcOscanBit,D3 ; clear the underscan/overscan bit if set BCLR #fSRsrc24Bit,D3 ; clear the 24b/32b sRsrc bit if set BCLR #fSRsrcXMemBit,D3 ; clear the 512k/1024k bit if set SUBA #spBlockSize,SP ; make room for the spBlock (done here so I can conveniently flush operror1) ; ; Get and install the interrupt handler. Call the SetInterrupt 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 OpError1 ; if not allocated, return bad MOVE.L A0,saveSQElPtr(A3) ; save the queue element for eventual disposal BSR EnableVGuts ; do it BNE OpError1 ; ; ; load the default gamma table from the slot resource list ; MOVE.L SP,A0 ; get pointer to block in A0 MOVE.B dCtlSlot(A1),spSlot(A0) ; copy the slot number CLR.W spID(A0) ; zero the spID.B,spExtDev.B CLR.B spTBMask(A0) ; we're going for an exact match to this card MOVE.W #CatDisplay,spCategory(A0) ; look for this card MOVE.W #TypVideo,spCType(A0) ; MOVE.W #DrSwApple,spDrvrSW(A0) ; MOVE.W #DrHwJMFB,spDrvrHW(A0) ; CLR.B spHWDev(A0) ; ???? _sNextTypesRsrc ; get the spsPointer MOVE.B #sGammaDir,spID(A0) ; look for the gamma directory _sFindStruct ; get that baby MOVE.B #128,spID(A0) ; get the default gamma table, (always 128) _sGetBlock ; we can use this since we want a ptr in sysheap BNE.S DoLinear ; if we can't find it, use linear one! ; ; skip over header ; MOVE.L spResult(A0),A0 ; point to head of the block MOVE.L A0,saveGammaPtrHead(A3) ; save head of the GammaPtr for disposal ADDA #2,A0 ; skip resID @Name TST.B (A0)+ ; skip over gamma name BNE.S @Name ; ADDA #1,A0 ; word align pointer MOVE.L A0,D0 ; get in d-reg AND.L #$FFFFFFFE,D0 ; round it MOVE.L D0,saveGammaPtr(A3) ; put it in private storage BRA.S OpenDone ; ; build a linear default gamma table ; DoLinear MOVEQ.L #gFormulaData,D0 ; get gamma table header size ADD #256,D0 ; and one byte per element for data _NewPtr ,SYS,CLEAR ; and clear it too BNE.S OpError1 ; die if allocation failed MOVE.L A0,saveGammaPtrHead(A3) ; save head of the GammaPtr for disposal MOVE.L A0,saveGammaPtr(A3) ; save a pointer to it MOVE.W #DrHwJMFB,gType(A0) ; MOVE.W #1,gChanCnt(A0) ; MOVE.W #256,gDataCnt(A0) ; MOVE.W #8,gDataWidth(A0) ; eight bits/value ADD #gFormulaData,A0 ; point to data table MOVE.W #$FF,D0 ; put linear data in table MOVEQ #0,D1 @Loop MOVE.B D1,(A0)+ ; write the value ADDQ #1,D1 DBRA D0,@Loop ; for all positions ; ; all done! ; OpenDone ADDA #spBlockSize,SP ; release the slot manager block MOVEQ #0,D0 ; no error EndOpen RTS ; return OpError1 MOVE.L dCtlStorage(A1),A0 ; dispose of private storage _DisposHandle ; do it ADDA #spBlockSize,SP ; get rid of spBlock OpError MOVE.L #OpenErr,D0 ; say can't open driver BRA.S EndOpen ******************************************************************* * * Video Driver Control Call Handler. There are ten calls- the nine * calls from the Bob driver and a new one that allows alteration of the * CLUT when operating as a direct device (24 bpp for us). * * (0) Reset (VAR mode, page: INTEGER; VAR BaseAddr: Ptr); * (1) KillIO * (2) SetMode(mode, page: INTEGER; VAR BaseAddr: Ptr); * (3) SetEntries ( Table: Ptr; Start,Count : integer ); * (4) SetGamma ( Table : Ptr ); * (5) GrayPage (page); * (6) SetGray (csMode = 0 for color, 1 for gray) * (7) SetInterrupt ( csMode = 0 for enable, 1 for disable) * (8) DirectSetEntries ( Table: Ptr; Start,Count : integer ); * (9) SetDefaultMode (mode); * * The Control Call Handler is broken up into 4 main steps: * * 1. Strip the upper byte of the DCE pointer (A1). It can be used in 32 bit mode. * 2. Get the pointer to private storage in A3 and strip the upper byte. * 3. Get the pointer to the csParams in A2. * 4. Get the csCode and dispatch the call to the right control call. * * Called by: * * Device Manager * * Traps and Utilities called: * * _StripAddress, appropriate control call * * Register usage: * * Input: * A0 = param block pointer * A1 = DCE pointer * * Output: * D0 = error code * * Locally used: * D0 = scratch, then returns error code as output * * A2 = cs parameters (ie. A2 <- csParam(A0)) (must be preserved) * A3 = ptr to private storage (passed to all control calls) * * Miscellaneous: * * None. * ******************************************************************* VideoCtl MOVE.L A0,-(SP) ; save work registers (A0 is saved because it is used by ExitDrvr) MOVE.L A1,D0 ; need to clean up the pointer to the DCE _StripAddress ; because it is used in 32 bit mode later MOVE.L D0,A1 ; in DisableVGuts MOVE.L dCtlStorage(A1),A3 MOVE.L (A3),D0 ; get pointer to private storage _StripAddress ; strip the hi byte for 32 bit addressing MOVE.L D0,A3 ; move back into A3 MOVE.L csParam(A0),D0 ; A2 <- Ptr to control parameters _StripAddress ; strip the hi byte for 32 bit addressing MOVE.L D0,A2 ; put into A2 MOVE.W csCode(A0),D0 ; get the opCode CMP.W #9,D0 ; IF csCode NOT IN [0..10] THEN BHI.S CtlBad ; Error, csCode out of bounds MOVE.W CtlJumpTbl(PC,D0.W*2),D0 ; Get the relative offset to the routine JMP CtlJumpTbl(PC,D0.W) ; GOTO the proper routine CtlJumpTbl DC.W VidReset-CtlJumpTbl ; $00 => VidReset DC.W CtlGood-CtlJumpTbl ; $01 => CtlGood DC.W SetVidMode-CtlJumpTbl ; $02 => SetVidMode DC.W SetEntries-CtlJumpTbl ; $03 => SetEntries DC.W SetGamma-CtlJumpTbl ; $04 => SetGamma DC.W GrayPage-CtlJumpTbl ; $05 => GrayPage DC.W SetGray-CtlJumpTbl ; $06 => SetGray DC.W SetInterrupt-CtlJumpTbl ; $07 => SetInterrupt DC.W DirectSetEntries-CtlJumpTbl ; $08 => DirectSetEntries DC.W SetDefaultMode-CtlJumpTbl ; $09 => SetDefault mode CtlBad MOVEQ #controlErr,D0 ; else say we don't do this one BRA.S CtlDone ; and return CtlGood MOVEQ #noErr,D0 ; return no error CtlDone MOVE.L (SP)+,A0 ; restore registers. BRA ExitDrvr ******************************************************************* * * VidReset resets the card to its default mode (1bpp). * * VidReset is broken up into 1 main steps: * * 1. Reset the card to 1 bpp mode. * * Called by: * * No one that I know of today. * * Traps and Utilities called: * * JMFBSetDepth, JMFBSetPage, GrayScreen * * Register usage: * * Input: * A2 - pointer to the csParams * A3 - pointer to the private storage * * Output: * D0 - error code * * csMode(A2) - new mode (1bpp) * csPage(A2) - new page (0) * csBaseAddr(A2) - base address * saveMode(A3) - new mode saved in privates * * Locally used: * D1 - used to pass the requested depth to JMFBSetDepth * D4 - used to pass the requested page to JMFBSetPage * * Miscellaneous: * * None. * ******************************************************************* VidReset MOVE #FirstVidMode,csMode(A2) ; return default mode MOVE #FirstVidMode,saveMode(A3) ; remember firstVidMode as the requested mode MOVE #1,D1 ; get default depth in D1 MOVEQ #0,D4 ; get page in D4 (used since SwapMMUMode uses D0) MOVE D4,csPage(A2) ; return the page BSR JMFBSetDepth ; set the depth from D1 BSR JMFBSetPage ; set the page from D4 MOVE.L saveBaseAddr(A3),csBaseAddr(A2) ; return the base address BSR GrayScreen ; paint the screen gray BRA.S CtlGood ; => no error ******************************************************************* * * SetVidMode sets the card to the specified mode and page. If either * is invalid, returns badMode error. If the card is already set to * the specified mode, then do nothing. * * SetVidMode is broken up into 7 main steps: * * 1. Check the requested mode against allowable modes and exit if bad. * 2. Check the requested page number against max pages and exit if bad. * 3. If the requested mode is the same as the current mode then exit. * 4. Get the gamma corrected value for half intensity gray. * 5. Set the entire CLUT to the value in above step prior to changing modes. * 6. Call JMFBSetDepth to change modes. * 7. Call JMFBSetPage to change pages (will reset the hw base address) * * Called by: * * Control Call Handler. * * Traps and Utilities called: * * ChkMode, ChkPage, _SwapMMUMode, WaitVSync, JMFBSetDepth, JMFBSetPage * * Register usage: * * Input: * A2 - pointer to the csParams * A3 - pointer to the private storage * * Output: * D0 - error code * * csBaseAddr(A2) - base address of frame buffer * * Locally used: * D0 - scratch * D1 - used to pass requested mode to ChkMode (comes back as depth) * - later used to pass depth to JMFBSetDepth * D2 - scratch * D3 - used to hold the gamma corrected half intensity value for gray * D4 - used to pass requested page to ChkMode * * A0 - used to point to CLUT address space * * Miscellaneous: * * None. * ******************************************************************* SetVidMode MOVE.W csMode(A2),D1 ; D1 = mode BSR ChkMode ; check mode, map to depth in D1 (1,2,4,8, or 24) BNE.S CtlBad ; => not a valid mode MOVE.W csPage(A2),D0 ; D0 = page MOVE.W D0,D4 ; use d4 as the parameter since SwapMMU mode uses D0 BSR ChkPage ; check page BNE.S CtlBad ; => not a valid page ; Only set the mode if it has changed ; JMFBSetDepth and JMFBSetPage update the saved data in the dCtlStorage SetEm MOVE.W csMode(A2),D2 ; D2 = mode CMP saveMode(A3),D2 ; has the mode changed? BEQ.S ModeOK1 ; => no, check the page ; remember the newly requested mode MOVE.W csMode(A2),saveMode(A3) ; remember requested mode ; set the entire color table to gray before switching to avoid screen anomalies MOVE.L saveGammaPtr(A3),A0 ; get pointer to gamma data structure MOVE GFormulaSize(A0),D3 ; get the size of formula data MOVE.W GDataCnt(A0),D2 ; get number of gamma entries LSR.W #1,D2 ; divide by two to find midpoint LEA GFormulaData(A0),A0 ; point to formula data ADD D3,A0 ; first correction table starts here MOVE.B (A0,D2),D3 ; get corrected gray from middle of red table MOVE.L saveHardBase(A3),A0 ; A0 <- base address of device. ADD.L #CLUT+CLUTDataReg,A0 ; add offset to color table data register for later ; switch to 32 bit addressing here since all calls to WaitVSync must be done in 32 bit mode, and ; we also need to be in 32 bit mode to get up to the CLUT. MOVEQ #true32b,D0 ; we'll be addr in 32 bit so get ready _SwapMMUMode ; swap to 32 bit mode MOVE D0,-(SP) ; save past addr mode on stack MOVE.W SR,-(SP) ; get the current interrupt level MOVEQ.L #7,D0 ; setup to get interrupt level AND.B (SP),D0 ; D0 now holds current interrupt level SUBQ #2,D0 ; BGE.S @itsOK ; if >= 2 then intr level is ok ORI.W #$0200,SR ; if <2 then raise intr level to at least 2 ANDI.W #$FAFF,SR ; may have to drop it to 2 @itsOK BSR WaitVSync ; wait for next blanking period (A0 saved) MOVE.L #$00,CLUTAddrReg-CLUTDataReg(A0) ; hit that baby (all writes to Trident hw must be longs!) MOVE.W #$FF,D2 ; get count @Repeat MOVE.L D3,(A0) ; put red (all writes to Trident hw must be longs!) MOVE.L D3,(A0) ; put green (all writes to Trident hw must be longs!) MOVE.L D3,(A0) ; put blue (all writes to Trident hw must be longs!) DBRA D2,@Repeat ; MOVE (SP)+,SR ; restore the status reg MOVE (SP)+,D0 ; restore past addr mode in D0 _SwapMMUMode ; swap back to previous addr mode BSR JMFBSetDepth ; set the depth, get rowbytes ModeOK1 BSR JMFBSetPage ; set the page NoChange MOVE.L saveBaseAddr(A3),csBaseAddr(A2) ; return the base address BRA CtlGood ; => return no error ******************************************************************* * * The SetEntries 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). * * This call has common code that is shared between SetEntries and DirectSetEntries. * * Before the entries in the CLUT are actually set up, they are first gamma corrected. * The gamma table has the following structure: * * record GammaTable of * gVersion : integer (0 for all current cards) * gType : integer (holds drHWId to identify board the table was measured for) * gFormulaSize : integer (size of gFormulaData in bytes, 0 for Apple cards) * gChanCnt : integer (number of gamma tables in gData, 1 for Apple cards) * gDataCnt : integer (number of elements in each channels correction table, 2**gDataWidth) * gDataWidth : integer (width of each element in a channels correction table) * gFormulaData : array [0..gFormulaSize] of byte (not used for Apple cards) * gData : array [0..gDataCnt] of byte (correction table data) * end * * SetEntries is broken up into 4 main steps: * * 1. If there is no requested color table or if we're in 24 bpp mode, then exit. * 2. Get the current gamma table. * 3. Construct a gamma corrected and hw specific color table on the stack. * 4. Write to the hardware in requested mode ( for mono BigScreens, use 1 channel only). * * Called by: * * Control Call Handler. * * Traps and Utilities called: * * _StripAddress, GetGammaCSpec, _SwapMMUMode, WaitVSync * * Register usage: * * Input: * A1 - pointer to the AuxDCE * A2 - pointer to the csParams * csTable -> table of colorSpecs (not colortable) * csStart -> where to start setting, or -1 * csCount -> # of entries to change * A3 - pointer to the private storage * * Output: * D0 - error code * * Locally used: * D0 - scratch * D1 - scratch * D2 - holds the reformatted cSpec that is hw dependent * D3 - scratch * D4 - Size of the stack color table buffer * D5 - GFlags word from private storage * D6 - holds the max number of entries to change as a f(mode) * - later used to save SR state * D7 - holds the csStart parameter * * A0 - scratch * A3 - points to the color spec table * A4 - pointer to gamma red table * A5 - pointer to gamma red table * A6 - pointer to gamma red table * * Miscellaneous: * * None. * ******************************************************************* SetEntries MOVE.L csTable(A2),D0 ; Check for a nil pointer BEQ CtlBad BTST #DirectModeFlag,GFlags(A3) ; SetEntries is not allowed for direct devices BNE CtlBad ; Indexed Mode (0) and Direct Mode (1) SetEntCom MOVEM.L A4-A6/D4-D7,-(SP) ; save registers for gamma (D4 saved by VideoCtl) MOVE.W GFlags(A3),D5 ; get GFlags word in D5 to be used to determine gray mode MOVE.L saveGammaPtr(A3),A0 ; get pointer to gamma table data structures LEA GFormulaData(A0),A4 ; get a pointer to the first gammatable ADDA GFormulaSize(A0),A4 ; MOVE.L A4,A5 ; get default pointer to green data (assuming gChanCnt=1) MOVE.L A4,A6 ; get default pointer to blue data (assuming gChanCnt=1) MOVE GDataWidth(A0),D7 ; get width of each entry in bits to be used later CMP #1,GChanCnt(A0) ; if only only one table, we're set BEQ.S OneTbl ; => just one table MOVE GDataCnt(A0),D0 ; get # entries in table MOVE D7,D1 ; copy it to goof around ADD #7,D1 ; round to nearest byte LSR #3,D1 ; get bytes per entry MULU D1,D0 ; get size of table in bytes ADDA D0,A5 ; calc base of green (red base + D0) ADDA D0,A6 ; calc base of blue ADDA D0,A6 ; calc base of blue (red base + D0 + D0) OneTbl ; get the maximum number of entries, zero based from a convenient table MOVE.W saveMode(A3),D1 ; get the current video mode SUB.W #FirstVidMode,D1 ; convert to index LEA CountTbl,A3 ; point to little table of counts MOVEQ #0,D6 ; clear the entire long (only need word tho!) MOVE.B (A3,D1),D6 ; pick the zero-based byte ; ; allocate a temporary color table on the stack. We'll pre-process all the entries that will ; change here so we can hit the hardware as quickly as possible. ; MOVE.W csCount(A2),D3 ; get the number of entries to change CMP.W D6,D3 ; is it in the allowable range? BHI BadExit ; if outside, then exit w/bad result MOVE.W csStart(A2),D0 ; get the start number to range check ADDQ.W #1,D0 BMI BadExit ; if csStart < -1 then it's out of range MOVE.L SP,D1 ; get stack MOVE.L D1,D0 ; copy stack NEG D0 ; get amount to subtract AND #$3,D0 ; get low bits BEQ.S StkOk ; => already long aligned SUB D0,SP ; else make stack long aligned StkOk MOVE.L D1,-(SP) ; save original stack on stack MOVE.L D3,D4 ; make a copy of the table size (zero-based!) ADDQ #1,D4 ; make it a counting number ASL #2,D4 ; multiply times 4 (always less than 1024) SUB.W D4,SP ; allocate the buffer ; ; construct the stack version of the color table. This table includes all translations and ; inversion required to drive the hardware. It looks like a color table, but each of the ; four components is only eight bits (rather than 16). ; MOVE.L SP,A0 ; copy the stack buffer pointer MOVE.L csTable(A2),D0 ; get colorSpec pointer in D0 _StripAddress ; clear upper byte for 32 bit mode MOVE.L D0,A3 ; put it in A3 @a BSR GetGammaCSpec ; go get a reformatted colorSpec in D2 MOVE.L D2,(A0)+ ; put the BBGGRRVV colorSpec in stack table DBRA D3,@a ; do it for all cSpecArray records ; Hit the hardware as quick as possible! MOVE.W csCount(A2),D3 ; get the number of entries to change again MOVE.L dCtlStorage(A1),A3 MOVE.L (A3),D0 ; get pointer to private storage again _StripAddress ; strip address for 32 bit addressing MOVE.L D0,A3 MOVEQ #true32b,D0 ; we'll be addr in 32 bit so get ready _SwapMMUMode ; swap over from 24 bit to 32 bit mode MOVE D0,D1 ; save past addr mode for later (can't use stack here!) MOVE.W SR,D6 ; get the current interrupt level MOVEQ.L #7,D0 ; setup to get interrupt level ROR.W #8,D6 ; roll to get the 3 interrupt bits in low byte AND.B D6,D0 ; D0 now holds current interrupt level ROL.W #8,D6 ; restore D6 since it holds the sr to be restored SUBQ #2,D0 ; BGE.S @itsOK ; if >= 2 then intr level is ok ORI.W #$0200,SR ; if <2 then raise intr level to at least 2 ANDI.W #$FAFF,SR ; may have to drop it to 2 @itsOK BSR WaitVSync ; wait for next VSync before writing to CLUT MOVE.L saveHardBase(A3),A3 ; point to the base address of device ADD.L #CLUT+CLUTDataReg,A3 ; add offset to get to the data register MOVE.W csStart(A2),D7 ; get the starting position (also indicates mode) BPL.S SeqWrite ; do sequence mode if its sequence IndexWrite MOVE.L (SP)+,D2 ; get a stack table reformatted colorSpec MOVE.L D2,CLUTAddrReg-CLUTDataReg(A3) ; write the addr to be modified to CLUT addr register LSR.L #8,D2 ; get red CLUT data in low byte of D2 IF NOT ProtoVRAM THEN BTST #MonoFlag,D5 ; if it's a monochrome monitor, only turn on 1 gun (red) BEQ.S @iAllThree ; if it's a color monitor (0), all 3 guns are active ELSE BRA.S @iAllThree ; for the prototype always turn all 3 guns on ENDIF MOVE.L #0,(A3) ; write black (off) to red MOVE.L #0,(A3) ; write black (off) to green MOVE.L D2,(A3) ; write blue to CLUT data register BRA.S @iJustBlue @iAllThree MOVE.L D2,(A3) ; write red to CLUT data register LSR.L #8,D2 ; get green CLUT data in low byte of D2 MOVE.L D2,(A3) ; write green to CLUT data register LSR.L #8,D2 ; get blue CLUT data in low byte of D2 MOVE.L D2,(A3) ; write blue to CLUT data register @iJustBlue DBRA D3,IndexWrite ; do for all (remember CLUT address autoincrements after blue) BRA.S SEDone ; all done with index mode so exit SeqWrite MOVE.L D7,CLUTAddrReg-CLUTDataReg(A3) ; write the start addr to be modified to CLUT addr register @b MOVE.L (SP)+,D2 ; get a stack table reformatted colorSpec LSR.L #8,D2 ; since sequence mode doesn't care about value field, flush byte BTST #MonoFlag,D5 ; If it's a monochrome monitor, only turn on 1 gun (red) BEQ.S @allThree ; if it's a color monitor (0), all 3 guns are active MOVE.L #0,(A3) ; write black (off) to red MOVE.L #0,(A3) ; write black (off) to green MOVE.L D2,(A3) ; write blue to CLUT data register BRA.S @JustBlue @allThree MOVE.L D2,(A3) ; write red to CLUT data register LSR.L #8,D2 ; get green CLUT data in low byte of D2 MOVE.L D2,(A3) ; write green to CLUT data register LSR.L #8,D2 ; get blue CLUT data in low byte of D2 MOVE.L D2,(A3) ; write blue to CLUT data register @JustBlue DBRA D3,@b ; do for all (remember CLUT address autoincrements after blue) ; All done! SEDone MOVE D1,D0 ; restore past addr mode in D0 _SwapMMUMode ; swap from 32 bit to 24 bit addressing MOVE D6,SR ; restore status register MOVE.L (SP)+,SP ; restore stack pointer MOVEM.L (SP)+,A4-A6/D4-D7 ; restore registers BRA CtlGood ; return O-Tay! BadExit MOVEM.L (SP)+,A4-A6/D4-D7 ; restore registers BRA CtlBad ; return an error code GetGammaCSpec ******************************************************************* * * GetGammaCSpec takes a Color Manager format colorSpec (see IM-V), performs weighted luminance * mapping to gray scales if necessary, performs gamma correction and returns in D2 a reformatted * colorSpec in the form BBGGRRVV where: * * BB = gamma corrected blue CLUT data * GG = gamma corrected green CLUT data * RR = gamma corrected red CLUT data * VV = 8 bit colorSpec value data (CLUT address for RGB triplet only used in index mode) * * GetGammaCSpec is broken up into 4 main steps: * * 1. Get the raw 16 bit values from the Mac OS color model and put into working registers * 2. Perform luminance mapping if gray mode is set (R=30%, G=59%, B=11%) * 3. Convert 16 bit format to 8 bit format to play with our hardware. The value field is * right justified in a word, and R,G,B fields are left justified. (See IM-V137) * 4. Perform gamma correction by indexing into appropriate R,G, or B gamma table, and pack * reformatted colorSpec into a 32 bit register, D2, in the form BBGGRRVV. * * Called by: * * SetEntries * * Traps and Utilities called: * * None. * * Register usage: * * Input: * * D5 - GFlags word where MSB identifies state of grayflag * D7 - contains width of CLUT channel * * A3 - points to colorSpec table * A4 - points to red gamma correction table * A5 - points to green gamma correction table * A6 - points to blue gamma correction table * * Output * * D2 - reformatted colorSpec in the form BBGGRRVV * A3 - incremented to point to next entry in colorSpec table * * Locally used * * D0 - to hold 16 bit red data from raw colorSpec * D1 - to hold 16 bit green data from raw colorSpec * D2 - to hold 16 bit blue data from raw colorSpec * D3 - to hold 16 bit value data from raw colorSpec (restored since it holds csCount) * ******************************************************************* MOVE.L D3,-(SP) MOVE.W (A3)+,D3 ; get value MOVE.W (A3)+,D0 ; get red MOVE.W (A3)+,D1 ; get green MOVE.W (A3)+,D2 ; get blue TST D5 ; test hi bit of the flags BPL.S NoGray ; if not set, don't luminence map BTST #DirectModeFlag,D5 ; test for direct mode flag BNE.S NoGray ; never luminance map if we're direct ; we're luminence mapping here MULU #$4CCC,D0 ; multiply by red weight MULU #$970A,D1 ; multiply by green weight MULU #$1C29,D2 ; multiply by blue weight ADD.L D1,D0 ; sum red and green ADD.L D2,D0 ; blue also BFEXTU D0{0:D7},D1 ; get gChanWidth bits for gamma table lookup MOVE.W D1,D0 ; copy into red register MOVE.W D1,D2 ; copy into blue register BRA.S WriteSP ; go on and write it in the stack buffer NoGray BFEXTU D0{16:D7},D0 ; get gChanWidth bits of red BFEXTU D1{16:D7},D1 ; get gChanWidth bits of green BFEXTU D2{16:D7},D2 ; get gChanWidth bits of blue WriteSP MOVE.B (A6,D2),D2 ; get gamma corrected blue (D2 = xxxxxxBB) LSL.L #8,D2 ; reposition blue (D2 = xxxxBBxx) MOVE.B (A5,D1),D2 ; get gamma corrected green (D2 = xxxxBBGG) LSL.L #8,D2 ; reposition blue/green (D2 = xxBBGGxx) MOVE.B (A4,D0),D2 ; get gamma corrected red (D2 = xxBBGGRR) LSL.L #8,D2 ; reposition blue/green/red (D2 = BBGGRRxx) MOVE.B D3,D2 ; put value byte into D2 (D2 = BBGGRRVV) MOVE.L (SP)+,D3 RTS ******************************************************************* * * SetGamma sets 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. Note that since the CLUT response curve of the AC/DC * chip is so close to the response of DAC's used on previous Apple cards, * that we let TFB tables thru too (GType=0), but only for the standard monitor!. * * SetGamma is broken up into 4 main steps: * * 1. if we're passed a nil table, then setup a linear one and skip to step 4. * 2. Get the gamma table and see if it's for us * 3. Copy the new gamma table. * 4. If we're operating as a direct device, then also set up the CLUT directly. * * Called by: * * Control Call Handler * * Traps and Utilities called: * * _DisposPtr, _NewPtr, _SwapMMUMode * * Register usage: * * Input: * A1 - pointer to the AuxDCE * A2 - pointer to the csParams * csGTable -> pointer to gamma table * A3 - pointer to the private storage * * Output: * D0 - error code * * Locally used: * D0 - scratch * D1 - used to create linear clut data index * D2 - scratch * D7 - scratch * * A0 - holds pointer to current gamma table * A4 - pointer to gamma red table (direct mode only) * A5 - pointer to gamma red table (direct mode only) * A6 - pointer to gamma red table (direct mode only) * * Miscellaneous: * * None. * ******************************************************************* SetGamma ; 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 a linear gamma table MOVE.L D0,A2 ; get pointer to new gamma table TST.W GVersion(A2) ; version = 0? BNE CtlBad ; => no, return error CMP.W #Standard,saveMonSense(A3) ; allow tfb table only for standard monitor BNE.S @chkHWMatch ; if not standard then it must be exact match TST.W GType(A2) ; test the hardware ID BEQ.S ChangeTable ; if 0, then accept a TFB table @chkHWMatch CMP.W #drHwJMFB,GType(A2) ; type = Bob the card? BNE CtlBad ; => no, return error TST.W gFormulaSize(A2) ; if gType=JMFB, then check for monID in gFormulaData BEQ.S ChangeTable ; if zero, then generic, so continue MOVE.W gFormulaData(A2),D0 ; get the monitor ID this table was intended for CMP.W saveID(A3),D0 ; is this the monitor? BEQ.S ChangeTable ; yes, so do it ADDQ #1,D0 ; was it -1? BNE CtlBad ; nope, so must be wrong monitor ; if new table is different size, reallocate memory ChangeTable MOVE.L saveGammaPtr(A3),A0 ; get current gamma in A0 MOVE GFormulaSize(A2),D0 ; get size of formula in new CMP GFormulaSize(A0),D0 ; same as current gamma table BNE.S @GetNew ; =>no, resize pointer MOVE GChanCnt(A2),D0 ; get number of tables in new CMP GChanCnt(A0),D0 ; same as current gamma table? BEQ.S @SizeOK ; => yes, data size ok BGT.S @GetNew ; => new one is bigger, save old one @NewSize Move.l saveGammaPtrHead(A3),A0 ; if new one smaller, _DisposPtr ; dispose old one CLR.L saveGammaPtrHead(A3) ; flag it's been disposed @GetNew MOVE GDataCnt(A2),D0 ; get number of entries MULU GChanCnt(A2),D0 ; multiply by number of tables ADD GFormulaSize(A2),D0 ; add size of formula data ADD #GFormulaData,D0 ; add gamma table header size _NewPtr ,Sys ; and allocate a new pointer BNE CtlBad ; => unable to allocate storage MOVE.L saveGammaPtrHead(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,saveGammaPtrHead(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 ADDA #GFormulaData,A0 ; point to tables ADDA D0,A0 ; point past monID, if present @ChanLoop MOVE.W #255,D0 ; loop count within each channel @entryLoop MOVE.B D0,(A0) ; write value NOT.B (A0)+ ; invert it to make table ramp properly DBRA D0,@entryLoop ; for each entry in channel DBRA D2,@ChanLoop ; and each channel GammaDone BTST #DirectModeFlag,GFlags(A3) ; If the mode is not direct, then all done BEQ CtlGood ; direct = 1, indexed = 0 MOVE.L saveGammaPtr(A3),A0 ; get pointer to gamma table data structures LEA GFormulaData(A0),A4 ; get a pointer to the first gammatable ADDA GFormulaSize(A0),A4 ; MOVE.L A4,A5 ; get default pointer to green data (assuming gChanCnt=1) MOVE.L A4,A6 ; get default pointer to blue data (assuming gChanCnt=1) MOVE GDataWidth(A0),D7 ; get width of each entry in bits to be used later CMP #1,GChanCnt(A0) ; if only only one table, we're set BEQ.S OnlyOneTbl ; => just one table MOVE GDataCnt(A0),D0 ; get # entries in table MOVE D7,D1 ; copy it to goof around ADD #7,D1 ; round to nearest byte LSR #3,D1 ; get bytes per entry MULU D1,D0 ; get size of table in bytes ADDA D0,A5 ; calc base of green (red base + D0) ADDA D0,A6 ; calc base of blue ADDA D0,A6 ; calc base of blue (red base + D0 + D0) OnlyOneTbl ; in direct modes we want a gamma corrected linear CLUT MOVE.L saveHardBase(A3),A0 ; get base addr of card ADD.L #CLUT+CLUTDataReg,A0 ; point to data reg of clut MOVEQ #true32b,D0 ; swap to 32 bit addr mode _SwapMMUMode MOVE D0,-(SP) ; save past addr mode for later MOVE.W SR,-(SP) ; get the current interrupt level MOVEQ.L #7,D0 ; setup to get interrupt level AND.B (SP),D0 ; D0 now holds current interrupt level SUBQ #2,D0 ; BGE.S @itsOK ; if >= 2 then intr level is ok ORI.W #$0200,SR ; if <2 then raise intr level to at least 2 ANDI.W #$FAFF,SR ; may have to drop it to 2 @itsOK BSR WaitVSync MOVE.L #0,CLUTAddrReg-CLUTDataReg(A0) ; start at index 0 MOVE.W #$FF,D0 ; set up for 256 rgb triplets MOVEQ #0,D1 ; d1 is used as the data index @1 MOVE.B (A4,D1),D2 ; temp move to d2 MOVE.L D2,(A0) ; write red (all Trident hw writes must be longs!) MOVE.B (A5,D1),D2 MOVE.L D2,(A0) ; write green (all Trident hw writes must be longs!) MOVE.B (A6,D1),D2 MOVE.L D2,(A0) ; write blue (all Trident hw writes must be longs!) ADDQ #1,D1 ; increment data index by 1 DBRA D0,@1 ; decrement loop counter and branch MOVE (SP)+,SR MOVE (SP)+,D0 ; restore past addr mode in D0 _SwapMMUMode BRA CtlGood ******************************************************************* * * GrayPage clears the specified page in the current mode to gray. If we * are operating on a direct device, GrayPage is also responsible for * setting up the CLUT directly (with linear and gamma corrected ramps). * * GrayPage is broken up into 4 main steps: * * 1. Check the requested mode against allowable modes and exit if bad. * 2. Check the requested page number against max pages and exit if bad. * 3. Call the GrayScreen utility * 4. If we're operating as a direct device, then also set up the CLUT directly. * * Called by: * * Control Call Handler * * Traps and Utilities called: * * GrayScreen, _SwapMMUMode, ChkMode, ChkPage * * Register usage: * * Input: * A1 - pointer to the AuxDCE * A2 - pointer to the csParams * csPage -> page number to gray * A3 - pointer to the private storage * * Output: * D0 - error code * * Locally used: * D0 - used to pass requested page to ChkPage * D1 - used to pass requested mode to ChkMode (comes back as depth) * D7 - scratch * * A0 - holds pointer to current gamma table * A4 - pointer to gamma red table (direct mode only) * A5 - pointer to gamma red table (direct mode only) * A6 - pointer to gamma red table (direct mode only) * * Miscellaneous: * * None. * ******************************************************************* GrayPage MOVE saveMode(A3),D1 ; D1 = mode MOVE D1,csMode(A2) ; force current mode, just in case for ChkPage BSR ChkMode ; convert mode to depth in D1 BNE CtlBad ; => not a valid depth MOVE csPage(A2),D0 ; D0 = page BSR ChkPage ; check page BNE CtlBad ; => not a valid page BSR GrayScreen ; paint the screen gray BTST #DirectModeFlag,GFlags(A3) ; If the mode is not direct, then all done BEQ CtlGood ; direct = 1, indexed = 0 MOVE.L saveGammaPtr(A3),A0 ; get pointer to gamma table data structures LEA GFormulaData(A0),A4 ; get a pointer to the first gammatable ADDA GFormulaSize(A0),A4 ; MOVE.L A4,A5 ; get default pointer to green data (assuming gChanCnt=1) MOVE.L A4,A6 ; get default pointer to blue data (assuming gChanCnt=1) MOVE GDataWidth(A0),D7 ; get width of each entry in bits to be used later CMP #1,GChanCnt(A0) ; if only only one table, we're set BEQ.S Only1Tbl ; => just one table MOVE GDataCnt(A0),D0 ; get # entries in table MOVE D7,D1 ; copy it to goof around ADD #7,D1 ; round to nearest byte LSR #3,D1 ; get bytes per entry MULU D1,D0 ; get size of table in bytes ADDA D0,A5 ; calc base of green (red base + D0) ADDA D0,A6 ; calc base of blue ADDA D0,A6 ; calc base of blue (red base + D0 + D0) Only1Tbl ; in direct modes we want a gamma corrected linear CLUT MOVE.L saveHardBase(A3),A0 ADD.L #CLUT+CLUTDataReg,A0 MOVEQ #true32b,D0 _SwapMMUMode MOVE D0,-(SP) ; save past addr mode for later MOVE.W SR,-(SP) ; get the current interrupt level MOVEQ.L #7,D0 ; setup to get interrupt level AND.B (SP),D0 ; D0 now holds current interrupt level SUBQ #2,D0 ; BGE.S @itsOK ; if >= 2 then intr level is ok ORI.W #$0200,SR ; if <2 then raise intr level to at least 2 ANDI.W #$FAFF,SR ; may have to drop it to 2 @itsOK BSR WaitVSync MOVE.L #0,CLUTAddrReg-CLUTDataReg(A0) MOVE.W #$FF,D0 MOVEQ #0,D1 @1 MOVE.B (A4,D1),D2 MOVE.L D2,(A0) MOVE.B (A5,D1),D2 MOVE.L D2,(A0) MOVE.B (A6,D1),D2 MOVE.L D2,(A0) ADDQ #1,D1 DBRA D0,@1 MOVE (SP)+,SR MOVE (SP)+,D0 ; restore past addr mode in D0 _SwapMMUMode BRA CtlGood ; => return no error ******************************************************************* * * SetGray sets 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. * * SetGray is broken up into 2 main steps: * * 1. If the monitor is monochrome always luminance map. * 2. Set GrayFlag in private storage based on requested mode. * * Called by: * * Control Call Handler. * * Traps and Utilities called: * * SetIntCom * * Register usage: * * Input: * A1 - pointer to the AuxDCE * A2 - pointer to the csParams * csmode -> gray or color mode * A3 - pointer to the private storage * * Output: * D0 - error code * * Locally used: * D1 - used as the bit position of grayFlag bit in GFlags word * * Miscellaneous: * * SetGray should always be followed by a SetEntries/GrayScreen call. * ******************************************************************* SetGray BTST #MonoFlag,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 #(15-GrayFlag),D1 ; set up for BFEXTU to point to GrayFlag BSR.S SetIntCom ; call common code BRA CtlGood ; all done ; ; this shared routine setup up a flag in GFlags. It takes a pointer to ; private storage in A3, and the bit field start location in D1 ; SetIntCom MOVE.B csMode(A2),D0 ; get boolean BFINS D0,GFlags(A3){D1:1} ; set flag bit RTS ; and return ******************************************************************* * * SetInterrupt enables (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. * * SetInterrupt is broken up into 3 main steps: * * 1. Set the IntDisFlag in private storage based on csMode * 2. If enable, then call EnableVGuts and save SaveSQElPtr in privates * 3. If disable, then call DisableVGuts * * Called by: * * Control Call Handler. * * Traps and Utilities called: * * SetIntCom, EnableVGuts, DisableVGuts * * Register usage: * * Input: * A1 - pointer to the AuxDCE * A2 - pointer to the csParams * csmode -> 0 enables, 1 disables * A3 - pointer to the private storage * * Output: * D0 - error code * * Locally used: * D1 - used as the bit position of IntDisFlag bit in GFlags word * * Miscellaneous: * * None. * ******************************************************************* SetInterrupt WITH VDPageInfo,SlotIntQElement MOVEQ #(15-IntDisFlag),D1 ; set up for BFEXTU to point to IntDisFlag BSR.S SetIntCom ; call common code BNE.S DisableThem ; if zero, then enable ; ; this code enables interrupts and installs the interrupt handler ; BSR.S EnableVGuts ; call common code BNE CtlBad ; error, flag problem BRA CtlGood ; and go home ; ; this code disables VBL interrupts, then removes the interrupt handler ; DisableThem BSR.S DisableVGuts ; jump to the disabling utility BRA CtlGood ; all done ; ; the following two routines are common code shared between the Open call ; and the SetInterrupt control call ; DisableVGuts ; gotta be in 32 bit mode prior to calling WaitVSync MOVEQ #true32b,D0 ; change to 32 bit addressing to get _SwapMMUMode ; at hardware MOVE D0,D3 ; save past addr mode for later (not using stack here) MOVE.W SR,-(SP) ; get the current interrupt level MOVEQ.L #7,D0 ; setup to get interrupt level AND.B (SP),D0 ; D0 now holds current interrupt level SUBQ #2,D0 ; BGE.S @itsOK ; if >= 2 then intr level is ok ORI.W #$0200,SR ; if <2 then raise intr level to at least 2 ANDI.W #$FAFF,SR ; may have to drop it to 2 @itsOK ;+++ BSR WaitVSync ; to be safe, wait for the next VBL CLR D0 ; clear D0.W MOVE.B dctlSlot(A1),D0 ; setup slot # for _SIntRemove MOVE.L saveHardBase(A3),A0 ; get the device base ADD.L #StopWatch+SWICReg,A0 ; point to StopWatch Interrupt and control register MOVE.L #7,(A0) ; disable both interrupts, but don't reset stowpwatch ??? MOVE D3,D0 ; restore past addr mode in D0 _SwapMMUMode MOVE.L saveSQElPtr(A3),A0 ; get the SQ element pointer _SIntRemove ; remove the interrupt handler MOVE.W (SP)+,SR ; restore the interrupt level RTS EnableVGuts MOVE.L saveSQElPtr(A3),A0 ; dispose of the VBL queue element LEA BeginIH,A2 ; save Pointer to interrupt handler MOVE.L A2,D0 _StripAddress MOVE.L D0,A2 MOVE.W #SIQType,SQType(A0) ; setup queue ID MOVE.L A2,SQAddr(A0) ; setup int routine address MOVE.L saveHardBase(A3),A2 ; get slot base addr ADD.L #StopWatch+SWClrVInt,A2 ; point to the Stopwatch interrupt clear register MOVE.L A2,SQParm(A0) ; pass this as the parameter MOVEQ.L #0,D0 ; parameter size to SInstall is not byte sized so clr whole long MOVE.B dctlSlot(A1),D0 ; _SIntInstall ; and do install BNE.S IntBad ADD.L #SWICReg-SWClrVInt,A2 ; point back to the Stopwatch Interrupt and Control Register MOVEQ #true32b,D0 ; change to 32 bit addressing to get _SwapMMUMode ; at hardware MOVE.L #5,(A2) ; no line interrupts, enable Vert Interrupts (and keep SRST = 1) _SwapMMUMode ; swap to previous mode (d0 still valid) CMP.W D1,D1 ; set Z-bit for good result RTS ; return home ; ; in the event there is a problem, return Z-flag off ; IntBad MOVEQ #1,D0 ; clear Z bit RTS ENDWITH ******************************************************************* * * The DirectSetEntries control call will allow color table animation in direct modes. * The code will be almost identical to the indexed modes SetEntries. * Note it will be the applications responsibility to restore the linear * ramps in all three CLUT channels upon completion of color table * animation. * * This call shares common code with SetEntries. * * DirectSetEntries is broken up into ***x*** main steps: * * 1. If there is no requested color table or if mode is indexed, then exit. * 2. Go and execute the SetEntries common code. * * Called by: * * Control Call Handler. * * Traps and Utilities called: * * Refer to SetEntries header. * * Register usage: * * Refer to SetEntries header. * * Miscellaneous: * * Refer to SetEntries header. * ******************************************************************* DirectSetEntries MOVE.L csTable(A2),D0 ; Check for a nil pointer BEQ CtlBad BTST #DirectModeFlag,GFlags(A3) ; DirectSetEntries is not allowed for indexed devices BEQ CtlBad ; Indexed Mode (0) and Direct Mode (1) BRA SetEntCom ******************************************************************* * * SetDefaultMode writes the requested card default mode into slot pRAM. * * This routine is called by Monitors when somebody selects an alternate * video mode family in the Options-Option dialog. Upon restart, PrimaryInit * will detect a change to the new sRsrc ID and set the card up for that * mode. The Trident card uses multiple members of video mode families * in the interlaced modes (RS170 and PAL) only. * * SetDefaultMode is broken up into 2 main steps: * * 1. Get the current PRAM record for the card. * 2. Modify the saved sRsrc ID and write out the record to PRAM. * * Called by: * * Control Call Handler (call is initiated only by Monitors cdev) * * Traps and Utilities called: * * _sReadPRAMRec, _sPutPRAMRec * * Register usage: * * Input: * A1 - pointer to the AuxDCE * A2 - pointer to the csParams * csmode -> new spID to be put into PRAM * A3 - pointer to the private storage * * Output: * None. * * Locally used: * A0 - used to point to slot parameter block * * Miscellaneous: * * None. * ******************************************************************* SetDefaultMode WITH spBlock ; ; set up a slot parameter block on the stack ; SUBA #spBlockSize,SP ; make an slot parameter block on stack MOVE.L SP,A0 ; get pointer to parm block now MOVE.B dCtlSlot(A1),spSlot(A0) ; put slot in pBlock CLR.B spExtDev(A0) ; external device = 0 ; ; read the slot pRAM to determine what the currently saved mode is. The first ; word is the board ID, followed by the default mode. Trident uses the vendoruse2 ; field to save the Monitor type. ; ;+++ vendoruse2 should really be the savedsRsrcID, check/change all occurances ; SUBA #SizesPRAMRec,SP ; allocate block for pRAM record MOVE.L SP,spResult(A0) ; point to it _sReadPRAMRec ; read it MOVE.B csMode(A2),savedSRsrcID(SP) ; return the result MOVE.L SP,spsPointer(A0) ; set up param block _sPutPRAMRec ADDA #SizesPRAMRec+spBlockSize,SP ; deallocate buffer BRA CtlGood ******************************************************************* * * VideoClose releases the device's private storage and removes the * interrupt handler. * * VideoClose is broken up into 4 main steps: * * 1. Clean up DCE pointer as it's used in 32 bit mode later * 2. Get a pointer to the driver private storage to release * 3. Call DisableVGuts to turn off interrupts, etc. * 4. Dispose of private storage memory. * * Called by: * * A/UX (I'm not aware of the Mac OS ever calling Close for video drivers) * * Traps and Utilities called: * * _StripAddress, DisableVGuts, _DisposPtr, _DisposHandle * * Register usage: * * Input: * A0 - parameter block pointer * A1 - pointer to the AuxDCE * * Output: * D0 - always returns no error. * * Locally used: * D0 - scratch * A3 - pointer to private storage * * Miscellaneous: * * None. * ******************************************************************* VideoClose MOVE.L A1,D0 ; need to clean up the pointer to the DCE _StripAddress ; because it is used in 32 bit mode later MOVE.L D0,A1 ; in DisableVGuts MOVE.L dCtlStorage(A1),A3 MOVE.L (A3),D0 ; get pointer to private storage _StripAddress ; strip hi byte for 32 bit addressing in DisableVGuts MOVE.L D0,A3 ; put back into A3 BSR DisableVGuts ; call utility to deactivate interrupts MOVE.L saveGammaPtrHead(A3),A0 ; get pointer to the head of gamma table _DisposPtr ; and dispose it MOVE.L dCtlStorage(A1),A0 ; Dispose of the private storage _DisposHandle ; MOVE.L saveSQElPtr(A3),A0 ; dispose of the VBL queue element _DisposPtr ; release it MOVEQ #0,D0 ; no error RTS ; and return ******************************************************************* * * Video Driver Status Call Handler. There are eight valid calls. No * new status calls have been introduced since Bob, although they * have been modified. * * (0) Error * (1) Error * (2) GetMode * (3) GetEntries * (4) GetPage * (5) GetPageBase * (6) GetGray * (7) GetInterrupt * (8) GetGamma * (9) GetDefault * * The Control Call Handler is broken up into 4 main steps: * * 1. Note : A1 (DCE pointer) is not StripAddressed for status calls! * 2. Get the pointer to private storage in A3 and strip the upper byte. * 3. Get the pointer to the csParams in A2. * 4. Get the csCode and dispatch the call to the right status call. * * Called by: * * Device Manager * * Traps and Utilities called: * * _StripAddress, appropriate control call * * Register usage: * * Input: * A0 = param block pointer * A1 = DCE pointer * * Output: * D0 = error code * * Locally used: * D0 = scratch, then returns error code as output * * A2 = cs parameters (ie. A2 <- csParam(A0)) (must be preserved) * A3 = ptr to private storage (passed to all control calls) * * Miscellaneous: * * None. * ******************************************************************* VideoStatus MOVE.L A0,-(SP) ; save a register MOVE.L dCtlStorage(A1),A3 MOVE.L (A3),D0 ; get pointer to private storage _StripAddress ; strip hi byte for 32 bit addressing MOVE.L D0,A3 ; put back in A3 MOVE.W csCode(A0),D0 ; get the opCode MOVE.L csParam(A0),A2 ; A2 <- Ptr to control parameters CMP.W #9,D0 ;IF csCode NOT IN [0..9] THEN BHI.S StatBad ; Error, csCode out of bounds. LSL.W #1,D0 ;Adjust csCode to be an index into the table. MOVE.W StatJumpTbl(PC,D0.W),D0 ;Get the relative offset to the routine. JMP StatJumpTbl(PC,D0.W) ;GOTO the proper routine. StatJumpTbl DC.W StatBad-StatJumpTbl ;$00 => Error DC.W StatBad-StatJumpTbl ;$01 => Error DC.W GetMode-StatJumpTbl ;$02 => GetMode DC.W GetEntries-StatJumpTbl ;$03 => GetEntries DC.W GetPage-StatJumpTbl ;$04 => GetPage DC.W GetPageBase-StatJumpTbl ;$05 => GetPageBase DC.W GetGray-StatJumpTbl ;$06 => GetGray DC.W GetInterrupt-StatJumpTbl ;$07 => GetInterrupt DC.W GetGamma-StatJumpTbl ;$08 => GetGamma DC.W GetDefaultMode-StatJumpTbl ;$09 => GetDefaultMode StatBad MOVEQ #statusErr,D0 ; else say we don't do this one BRA.S StatDone ; and return StatGood MOVEQ #noErr,D0 ; return no error StatDone MOVE.L (SP)+,A0 ; restore registers. BRA ExitDrvr ******************************************************************* * * GetMode returns the current operating mode in csMode, the current * display page in csPage, and the base address of the frame buffer * in csBaseAddr. * * GetMode is broken up into 3 main steps: * * 1. Copy the current saved mode into csMode(A2). * 2. Copy the current saved page into csPage(A2). * 3. Copy the current saved baseaddr into csBaseAddr(A2). * * Called by: * * Status Call Handler. * * Traps and Utilities called: * * None. * * Register usage: * * Input: * A1 - pointer to the AuxDCE * A2 - pointer to the csParams * A3 - pointer to the private storage * * Output: * D0 - error code. * * Locally used: * None. * * Miscellaneous: * * None. * ******************************************************************* GetMode MOVE.W saveMode(A3),csMode(A2) ; return the mode MOVE.W savePage(A3),csPage(A2) ; return the page number MOVE.L saveBaseAddr(A3),csBaseAddr(A2) ; and the base address BRA.S StatGood ; => return no error ******************************************************************* * * GetEntries reads the current contents of the CLUT. * * GetEntries is broken up into 4 main steps: * * 1. Get the pointer to the output table and strip upper byte. * 2. Range check the requested index count. * 3. If index mode write all value fields to table. * 4. Read the CLUT data registers and write data (components) to table. * * Called by: * * Status Call Handler. * * Traps and Utilities called: * * _StripAddress, _SwapMMUMode * * Register usage: * * Input: * A1 - pointer to the AuxDCE * A2 - pointer to the csParams * A3 - pointer to the private storage * * Output: * D0 - error code * * Locally used: * D0 - scratch * D1 - scratch and loop counter * D2 - used to hold the value index in indexed modes * D3 - holds max number of valid entries in current depth mode * D4 - loop counter for CLUT reads * * A0 - pointer to output table * * Miscellaneous: * * Note that due to gamma correction, the data in the CLUT will probably * not be the data that you wrote with SetEntries or DirectSetEntries (unless * the gamma table was a linear one). * ******************************************************************* GetEntries MOVE.L csTable(A2),D0 ; Check for a nil pointer BEQ.S StatBad _StripAddress ; strip hi byte prior to 32 bit addressing MOVE.L D0,A0 ; A0 <- pointer to table ; calculate the index range in D3 MOVE.W saveMode(A3),D1 ; get the current video mode SUB.W #FirstVidMode,D1 ; convert to index LEA CountTbl,A3 ; point to little table of counts MOVEQ #0,D3 ; clear the long (only need word size tho!) MOVE.B (A3,D1),D3 ; pick the zero-based byte MOVE.W csCount(A2),D4 ; get the count TST.W D4 BMI.S StatBad CMP.W D3,D4 ; D4-D3 > 0 (req count > max count) then bad BHI.S StatBad MOVE.W D4,D2 ; make a copy of the count CMP.W #-1,csStart(A2) ; is it index or sequence mode? BEQ.S GECom ; if index, then continue MOVE.W D4,D1 ; copy count into another loop counter ADD.W csStart(A2),D2 ; get last index @1 MOVE.W D2,value(A0,D1*8) ; write the index into the table SUBQ #1,D2 ; decrease index DBRA D1,@1 ; for all indices GECom MOVE.L dCtlStorage(A1),A3 MOVE.L (A3),D0 ; get pointer to private storage _StripAddress ; strip hi byte prior to 32 bit addressing MOVE.L D0,A3 ; put back into A3 MOVE.L saveHardBase(A3),A3 ; A3 <- base address of device ADD.L #CLUT+CLUTDataReg,A3 ; Add offset to CLUT read register MOVEQ #true32b,D0 _SwapMMUMode @Repeat MOVE.W value(A0),D1 ; get the next position in D1 CMP.W D3,D1 ; Is this request in range? BHI.S @Until ; if hi, then no, the request is invalid MOVE.L D1,CLUTAddrReg-CLUTDataReg(A3) ; set the CLUT to read from this address MOVE.L (A3),D1 ; get red MOVE.B D1,rgb+red(A0) ; write hi byte MOVE.B D1,rgb+red+1(A0) ; write lo byte MOVE.L (A3),D1 ; get green MOVE.B D1,rgb+green(A0) ; write hi byte MOVE.B D1,rgb+green+1(A0) ; write lo byte MOVE.L (A3),D1 ; get blue MOVE.B D1,rgb+blue(A0) ; write hi byte MOVE.B D1,rgb+blue+1(A0) ; write lo byte @Until ADDQ.L #colorSpecSize,A0 ; advance A0 to the next color table element DBRA D4,@Repeat ; and loop until done _SwapMMUMode BRA StatGood ; => return no error ******************************************************************* * * GetPage returs the number of pages in the specified mode. * Note that this routine is the only one that deals with non-zero * based page counts. All of the other ones, including the equates * are zero based! * * GetPage is broken up into 2 main steps: * * 1. Call ChkMode to see if mode is a valid one. * 2. Get the number of pages from the misc. param. table as a f(memorysize) * * Called by: * * Status Call Handler. * * Traps and Utilities called: * * ChkMode * * Register usage: * * Input: * A1 - pointer to the AuxDCE * A2 - pointer to the csParams * csMode - screen depth * A3 - pointer to the private storage * * Output: * D0 - error code. * * csPage(A2) - number of pages for current mode and memorysize * * Locally used: * D1 - scratch * D2 - holds mode and used to index into misc. param. table * * A0 - points to the active hw video parameters * * Miscellaneous: * * None. * ******************************************************************* GetPage MOVE csMode(A2),D1 ; get the mode MOVE D1,D2 ; keep a copy BSR ChkMode ; is this mode OK? BNE StatBad ; => not a valid mode SUB #FirstVidMode,D2 ; mode, zero-based MOVE.L saveVidParms(A3),A0 ; get pointer to vid parameters BTST #RAM512KFlag,GFlags(A3) ; how much RAM? BNE.S @1 ; if TRUE, then 512K of RAM MOVE.B (D_Pages1024,A0,D2),D1 ; get the number of video pages EXT.W D1 ; extend to word sized (especially important for -1 invalid case) BRA.S @2 ; @1 MOVE.B (D_Pages512,A0,D2),D1 ; EXT.W D1 ; extend to word sized (especially important for -1 invalid case) @2 ADDQ.W #1,D1 ; convert 0 based page count to non 0 based MOVE.W D1,csPage(A2) ; return page count (high byte zero from ChkMode) BRA StatGood ; => return no error GetPageBase ******************************************************************* * * GetPageBase returns the base address for the specified page * in the current mode * * GetPageBase is broken up into 6 main steps: * * 1. Call ChkMode to see if mode is a valid one. * 2. Call ChkPage to see if page is a valid one. * 3. Get the rowbytes and screenrows from the misc. param. table * 4. Calculate base address (page num * rowbytes * screenrows) * 5. Call GetBaseOffset to get additional offset if any and add. * 6. Add to slot space of the card (Fs000000). * * Called by: * * Status Call Handler. * * Traps and Utilities called: * * ChkMode, ChkPage, GetBaseOffset * * Register usage: * * Input: * A1 - pointer to the AuxDCE * A2 - pointer to the csParams * csPage - display page number * A3 - pointer to the private storage * * Output: * D0 - error code * * csBaseAddr(A2) - base address * * Locally used: * D0 - used to pass page number to ChkPage * - later used to return base offset from GetBaseOffset * D1 - used to pass mode to ChkMode and returns with depth mode * - later used to index into misc. parameters * - later used to pass to save interim calc * * Miscellaneous: * * None. * ******************************************************************* MOVE saveMode(A3),D1 ; get the current mode MOVE D1,csMode(A2) ; force current mode, just in case for ChkPage BSR ChkMode ; convert to depth in D1 ; (assume current mode ok - we set it, after all) MOVE.W csPage(A2),D0 ; get the requested page BSR ChkPage ; is the page valid? BNE StatBad ; => no, just return MOVE saveMode(A3),D1 ; get the current "real" mode SUB #FirstVidMode,D1 ; make it 0 based MOVE.L saveVidParms(A3),A0 ; point to data table MULU (D_RowBytes,A0,D1*2),D0 ; calc page * rowBytes MULU D_Height(A0),D0 ; calc page * rowBytes * height MOVE.L D0,D1 ; move page pass to D1 since GetBaseOffset returns D0 BSR GetBaseOffset ; get appropriate base address in D0 ADD.L D1,D0 ; add together into D0 ADD.L saveHardBase(A3),D0 ; add base address for card BTST #sRsrc32Bit,GFlags(A3) ; check for 32 bit sRsrc (base address = Fsxx xxxx) BNE.S @saveIt ; if it is 32 bit sRsrc page base address is setup right BFEXTU D0{4,4},D1 ; else it's 24 bit (Fssx xxxx) so get slot number BFINS D1,D0{8,4} ; and insert it into D0 to form Fssx xxxx @saveit MOVE.L D0,csBaseAddr(A2) ; return the base address BRA StatGood ; => return no error ******************************************************************* * * GetGray returns a boolean, set true if luminance mapping is on * * GetGray is broken up into 1 main steps: * * 1. Get the GrayFlag state from private storage and put in csMode. * * Called by: * * Status Call Handler. * * Traps and Utilities called: * * None. * * Register usage: * * Input: * A2 - pointer to the csParams * A3 - pointer to the private storage * * Output: * D0 - always returns good error code * * csMode(A2) - boolean indicating flag state * * Locally used: * D0 - scratch * * Miscellaneous: * * None. * ******************************************************************* GetGray MOVEQ #(15-GrayFlag),D1 ; set up for BFEXTU GetFlagCom BFEXTU GFlags(A3){D1:1},D0 ; get the state of flag MOVE.B D0,csMode(A2) ; return value BRA StatGood ; => and return ******************************************************************* * * GetInterrupt returns a boolean, set true if interrupts are disabled. * * GetInterrupt is broken up into 1 main steps: * * 1. Get the IntDisFlag state from private storage and put in csMode. * * Called by: * * Status Call Handler. * * Traps and Utilities called: * * None. * * Register usage: * * Input: * A2 - pointer to the csParams * A3 - pointer to the private storage * * Output: * D0 - always returns good error code * * csMode(A2) - boolean indicating flag state * * Locally used: * D0 - scratch * * Miscellaneous: * * None. * ******************************************************************* GetInterrupt MOVEQ #(15-IntDisFlag),D1 ; set up BFEXTU to point at IntDisFlag BRA.S GetFlagCom ; and use common code ******************************************************************* * * GetGamma returns the pointer to the current gamma table * * GetGamma is broken up into 1 main steps: * * 1. Retrieve the gamma pointer from privates and put in csGTable. * * Called by: * * Status Call Handler. * * Traps and Utilities called: * * None. * * Register usage: * * Input: * A2 - pointer to the csParams * A3 - pointer to the private storage * * Output: * D0 - always returns good error code * * Locally used: * None. * * Miscellaneous: * * None. * ******************************************************************* GetGamma MOVE.L saveGammaPtr(A3),csGTable(A2) ; return the pointer to the structure BRA StatGood ; and return a good result ******************************************************************* * * GetDefaultMode reads the card default mode from slot pRAM. * * GetDefaultMode is broken up into 2 main steps: * * 1. Read the PRAM record. * 2. Return the result in csMode * * Called by: * * Status Call Handler. * * Traps and Utilities called: * * _sReadPRAMRec * * Register usage: * * Input: * A1 - pointer to the AuxDCE * A2 - pointer to the csParams * * Output: * D0 - always returns good status * * Locally used: * A0 - pointer to slot parameter block * * Miscellaneous: * * None. * ******************************************************************* GetDefaultMode WITH spBlock ; ; set up a slot parameter block on the stack ; SUBA #spBlockSize,SP ; make an slot parameter block on stack MOVE.L SP,A0 ; get pointer to parm block now MOVE.B dCtlSlot(A1),spSlot(A0) ; put slot in pBlock CLR.B spExtDev(A0) ; external device = 0 ; ; read the slot pRAM to determine what the currently saved mode is. The first ; byte is the board ID, followed by the default mode. ; SUBA #SizesPRAMRec,SP ; allocate block for pRAM record MOVE.L SP,spResult(A0) ; point to it _sReadPRAMRec ; read it MOVE.B savedSRsrcID(SP),csMode(A2) ; return the result ADDA #SizesPRAMRec+spBlockSize,SP ; release buffer BRA StatGood ; ENDWITH ******************************************************************* * * Exit from control or Status. * ******************************************************************* ExitDrvr BTST #NoQueueBit,ioTrap(A0) ; no queue bit set? BEQ.S GoIODone ; => no, not immediate RTS ; otherwise, it was an immediate call GoIODone MOVE.L JIODone,A0 ; get the IODone address JMP (A0) ; invoke it *===================================================================== * * Utilities * *===================================================================== ******************************************************************* * * GetXtndSense reads the extended sense code from the sense lines. * In this driver, we are looking for the Sarnoff breakout box, which * has the sense lines assigned as 010100. Note that the returned sense * is of the format bc ac ab, where the first two bits are read when a * is set high, the second two bits are read when b is set high, and the * third two bits are read when c is set high. a, b, and c correspond to * sense lines 2, 1, and 0 where 2 is the msb. * * Called by: * * PrimaryInit, VideoOpen * * Traps and Utilities called: * * None. * * Register usage: * * Input: * * A1 - card base address * D1 - offset to JMFB CSR (contains sense lines) * * Output: * D0 - returns the extended sense. * * Locally used: * D2 - scratch (saved and restored) * D3 - scratch (used to hold the sense line to be output to the CSR * (i.e. 100, 010, or 001) * D4 - scratch used to build up the data to be output to the CSR * D5 - holds the number of bits to shift to get the sense code in the right place * (can't use immediate since max valid shift count is only 8 and we need 9) * * Miscellaneous: * * 1. Must be called in 32 bit addressing mode. * ******************************************************************* GetXtndSense MOVEM.L D2-D6,-(SP) ; save D2 working register CLR D0 ; initialize the return value MOVE.L #9,D5 ; initialize the number of bits to shift due to byte swapping MOVE.L #readBC,D3 ; set up 1 bit to be output LSL D5,D3 ; shift up due to byte swapping MOVE.L (A1,D1.L),D4 ; get current state of the JMFB CSR ANDI.W #MaskSenseLine,D4 ; Ensure sense lines will be written out as 000 OR.L D3,D4 ; write out MOVE.L D4,(A1,D1.L) ;+++ BFINS D3,(A1,D1.L){20:3} ; set a in sense reg high (This doesn't work to the card!) BFEXTU (A1,D1.L){20:3},D2 ; read the sense register a,b,c MOVE.B D2,D0 ; move into return register LSL.B #2,D0 ; move over 2 bits for next one MOVE.L #readAC,D3 ; set up 1 bit to be output LSL D5,D3 ; shift up due to byte swapping MOVE.L (A1,D1.L),D4 ; get current state of the JMFB CSR ANDI.W #MaskSenseLine,D4 ; Ensure sense lines will be written out as 000 OR.L D3,D4 ; write out MOVE.L D4,(A1,D1.L) ;+++ BFINS D3,(A1,D1.L){20:3} ; set b in sense reg high (This doesn't work to the card!) BFEXTU (A1,D1.L){20:3},D2 ; read the sense register a,b,c MOVE.B D2,D6 ; save bit c ANDI.B #1,D6 ; and only bit c LSR.B #1,D2 ; move bit a over 1 to form 2 bit code OR.B D6,D2 ; form it OR.B D2,D0 ; move into return register LSL.B #2,D0 ; move over 2 bits for next one MOVE.L #readAB,D3 ; set up 1 bit to be output LSL.L D5,D3 ; shift up due to byte swapping MOVE.L (A1,D1.L),D4 ; get current state of the JMFB CSR ANDI.W #MaskSenseLine,D4 ; Ensure sense lines will be written out as 000 OR.L D3,D4 ; write out MOVE.L D4,(A1,D1.L) ;+++ BFINS D3,(A1,D1.L){20:3} ; set c in sense reg high (This doesn't work to the card!) BFEXTU (A1,D1.L){20:3},D2 ; read the sense register a,b,c LSR.L #1,D2 ; shift a,b into lo 2 bits OR.B D2,D0 ; move into return register MOVEM.L (SP)+,D2-D6 ; restore D2 RTS ******************************************************************* * * ChkMode maps the mode to a depth (1, 2, 4, 8, or 16 (really 24 BPP)), and then * determines if this request is a valid one as a function of memory * configuration and connected monitor type. This routine is also responsible * for controlling the state of the DirectModeFlag. It is set for 24 BPP and * clear for all other modes. * * ChkMode is broken up into 3 main steps: * * 1. Make the mode request zero-based and range check, exit if bad. * 2. Convert mode request to depth. * 3. Determine if valid mode based on the table below. * * Called by: * * SetVidMode, GrayPage, GetPage, GetPageBase * * Traps and Utilities called: * * None. * * Register usage: * * Input: * D1 - Mode (in spID form) * A3 - pointer to the private storage * * Output: * Equal flag is set if mode is ok. * * Locally used: * D0 - scratch (trashed) * * Miscellaneous: * * 1. This routine implements the valid mode table in the Elmer Fudd * software ERS, and is repeated here. * * 640x480 640x870 1152x870 640x480 (NTSC oscan) 768x576 (PAL oscan) * 512x384 512x384 (NTSC uscan) 616x460 (PAL uscan) * A B A B A B A B A B * * 1BPP NI Y Y Y Y Y Y - - - - * I - - - - - - Y N Y N * IC - - - - - - N Y N Y * -------------------------------------------------------------------------------- * 2BPP NI Y Y Y Y Y Y - - - - * I - - - - - - Y N Y N * IC - - - - - - N Y N Y * -------------------------------------------------------------------------------- * 4BPP NI Y Y Y Y Y Y - - - - * I - - - - - - Y N Y N * IC - - - - - - N Y N Y * -------------------------------------------------------------------------------- * 8BPP NI Y Y N Y N Y - - - - * I - - - - - - Y N (uscan only!)Y N * IC - - - - - - N Y N Y * -------------------------------------------------------------------------------- * 24BPP NI N Y - - - - - - - - * I - - - - - - N Y N Y (uscan only!) * IC - - - - - - - - - - * -------------------------------------------------------------------------------- * * Legend: NI - NonInterlaced, I - Interlaced, IC - Interlaced with Convolution * A - 512K vRAM, B - 1024K vRAM * * Y - Mode Valid, N - Mode Invalid, '-' - Not Applicable (Mode Invalid) * * 2. The mode that is passed in to this routine (in D1) is the sResource list parameter * ID number and has a range between FirstVidMode and FifthVidMode ($80-$84). To * generate a screen depth from this parameter, it is desirable to make it 0 based. * The process is summarized by: * * parameter ID 0 based Depth * * $80 (1BPP) 0 (1BPP) 1 (1BPP) * $81 (2BPP) 1 (2BPP) 2 (2BPP) * $82 (4BPP) == Make it 0 based => 2 (4BPP) == Form Depth => 4 (4BPP) * $83 (8BPP) 3 (8BPP) 8 (8BPP) * $84 (24BPP) 4 (24BPP) 16 (24BPP)** * * ** Note that the returned depth for 24 BPP is really 16 not 24 or 32 as expected! * * 3. Certain modes are only allowed for certain monitors. For instance, 24 bpp is only * allowed on the small screens (and not in PAL oscan mode). The local variable * BigScreen is used in this routine. * ******************************************************************* ChkMode SUB #FirstVidMode,D1 ; make it 0 based BMI.S ModeBad ; =>bad mode, return CMP #Mode24BPP,D1 ; range check the mode parameter BGT.S ModeBad ; exit with error if too big BCLR #DirectModeFlag,GFlags(A3) ; anticipate that it's not 24 BPP MOVEQ #Depth1BPP,D0 ; convert mode request into depth LSL D1,D0 MOVE D0,D1 CMP.W #Depth4BPP,D1 ; all 1,2,4 BPP modes are OK for all monitors with 512K BLE.S ModeOK BTST #RAM512KFlag,GFlags(A3) ; check to see if card has 512K (1) or 1024K (0) BNE.S @512K ; branch to the 512K section CMP.W #Depth8BPP,D1 ; 8 BPP mode is OK for all monitors with 1024K BEQ.S ModeOK BTST #BigScreen,GFlags(A3) ; is it a small screen (0) or larger screen (1) BNE.S ModeBad ; 24 BPP mode is only allowed on the small screen BTST #sRsrc32Bit,GFlags(A3) ; make sure that we're an sRsrc that supports 24 bpp BEQ.S ModeBad ; if 0 then we're 24 bit sRsrc and no 24 bpp! BTST #PALFlag,moreGFlags(A3) ; check for PAL since 24 bpp is not supported in overscan mode BEQ.S @notPAL ; if it's not PAL, then 24 bpp mode request is ok BTST #underScanFlag,moreGFlags(A3) ; if it is PAL, check to see if it's underscan BEQ.S ModeBad ; if it is not underscan then the mode request is bad @notPAL BSET #DirectModeFlag,GFlags(A3) ; must be 24 BPP and the 640x480 small screen BRA.S ModeOK ; @512K BTST #BigScreen,GFlags(A3) ; is it a small screen (0) or larger screen (1) BNE.S ModeBad ; depths > 4 BPP are only supported on small screen BTST #PALFlag,moreGFlags(A3) ; special case for PAL oScan as it only supports 1,2,4 bpp with 1 bank BEQ.S @cont512K ; if it's not PAL, then don't do next check BTST #UnderScanFlag,moreGFlags(A3) ; check to see if we're overscanning BEQ.S ModeBad ; if we are then bad news so get out with error. @cont512K CMP.W #Depth8BPP,D1 ; 8 BPP is the max for small screen with 512K vRAM BNE.S ModeBad ModeOK CMP.W D1,D1 BRA.S EndCM ModeBad ST D1 ; set if error TST.B D1 ; and test condition EndCM RTS ******************************************************************* * * ChkPage checks to see if the page number in D0 is valid for the depth in D1, * given the amount of RAM on the card. * * ChkPage is broken up into 2 main steps: * * 1. Get the max number of pages allowed in current mode * 2. Compare with request and return EQ if valid * * Called by: * * SetVidMode, GrayPage, GetPageBase * * Traps and Utilities called: * * None. * * Register usage: * * Input: * D0 - page * * A2 - pointer to the csParams * A3 - pointer to the private storage * * csMode(A2) - current mode * * Output: * Set equal flag in SR if valid * * Locally used: * D2 - used to form mode and zero based mode and indexes into misc params. * D3 - used to hold the max number of valid pages * A1 - pointer to the hw setup parameters * * Miscellaneous: * * None. * ******************************************************************* ChkPage MOVEM.L D2-D3/A0-A1,-(SP) ; save work registers TST.W D0 ; check for bad value (negative) BMI.S PageBad MOVEQ #0,D3 ; clear D3 (at least word size) MOVE.W csMode(A2),D2 ; get offset to page data SUB.W #FirstVidMode,D2 ; zero-based offset in D2 MOVE.L saveVidParms(A3),A1 ; get pointer to data tables BTST #RAM512KFlag,GFlags(A3) ; 512K (0) or 1024K (1) BNE.S @1 ; if <> 0, then 1024K MOVE.B (D_Pages1024,A1,D2),D3 ; get max number of pages EXT.W D3 CMP.W D3,D0 ; is it a valid page? BRA.S @2 @1 MOVE.B (D_Pages512,A1,D2),D3 ; get max number of pages EXT.W D3 CMP.W D3,D0 ; @2 SGT D2 ; set flag if too big TST.B D2 ; and test condition BRA.S EndCP PageBad ST D2 TST.B D2 EndCP MOVEM.L (SP)+,D2-D3/A0-A1 ; restore work registers RTS ******************************************************************* * * WaitVSync waits for vertical blanking. * * Called by: * * SetVidMode, SetEntries, DisableVGuts, JMFBSetDepth. * * Traps and Utilities called: * * None. * * Register usage: * * Input: * A1 - pointer to the AuxDCE * A2 - pointer to the csParams * A3 - pointer to the private storage * * Output: * None. * * Locally used: * D0 - working register to hold the VSP~ state (saved) * A0 - used to point to the stopwatch status register (saved) * * Miscellaneous: * * 1. The VSP~ state is obtained by reading 1 bit in the StopWatch * Status Register. This bit is in bit position 2 * of the least signifcant byte when viewed from the 68020 world. * If you're looking here, you've probably already figured out * the byte swapping mess! Refer to the JMFB Spec to see the * address mapping requirement. * * IMPORTANT ... The sensing of the VSP~ register from Stopwatch is * inverted (from that defined in the spec) due to NuBus, so when a * vertical state is entered, we will read a 1, not a 0 !!!! * * 2. The BFEXTU instruction is used to extract the VSP~ state into * a working register. The offset is 29 bits into the register * (bit 0 is MSB of the long word, so bit 29 is bit 2 of the * least significant byte of the long word). The data width of * VSP~ is 1 bit. * * 3. The first loop waits for the VSP~ state to transition from 0 * to 1 (inverted from 1 -> 0) signifying that the vertical sync * pulse state was just entered. When VSP goes zero, we know that * the state is now vertical back porch. * * 4. The second loop waits for the VSP~ state to transition * to 0 (nverted 1) indicating that the vertical sync pulse state * has been exited. * * 5. The last loop waits for the VSP~ state to transition from 0 * to 1 again (inverted from 1 -> 0), insuring that we have delayed * for at least 1 vertical blanking period and that we are now at * the start of the next one. * * 6. IMPORTANT - 32 bit addressing must be in effect prior to calling * this utility subroutine! * ******************************************************************* WaitVSync MOVEM.L A0/D0,-(SP) ; save work registers MOVE.W SR,-(SP) ; get the current interrupt level MOVEQ.L #7,D0 ; setup to get interrupt level AND.B (SP),D0 ; D0 now holds current interrupt level SUBQ #2,D0 ; BGE.S @itsOK ; if >= 2 then intr level is ok ORI.W #$0200,SR ; if <2 then raise intr level to at least 2 ANDI.W #$FAFF,SR ; may have to drop it to 2 @itsOK MOVE.L saveHardBase(A3),A0 ; A0 <- slot base addr ADD.L #StopWatch+SWStatusReg,A0 ; point to stapwatch status register ; detect the 1 -> 0 transition of VSP~ signifying we've entered the vertical sync pulse state @0 BFEXTU (A0){29:1},D0 CMP.B #1,D0 BNE.S @0 ; detect the 0 -> 1 transition of VSP~ signifying we've exited the vertical sync pulse state @1 BFEXTU (A0){29:1},D0 CMP.B #0,D0 BNE.S @1 ; detect the 1 -> 0 transition of VSP~ again ensuring that we've delayed at least 1 vertical blanking ; period and it is now at the beginning of the next one! @2 BFEXTU (A0){29:1},D0 CMP.B #1,D0 BNE.S @2 MOVE.W (SP)+,SR ; restore interrupt state MOVEM.L (SP)+,A0/D0 ; restore work registers RTS ******************************************************************* * * JMFBSetDepth sets the JMFB up for the requested depth mode. The setup * is identical to primaryinit with the following exception, the clock * generation chip is not set up here for all modes except NTSC mode because * the setup would be redundant. In addition it is only necessary to change * the clock generation chipÕs timing in modes that support convolution, since * that is the only mode where more than one dot clock may be necessary. * The dot clock for interlaced ops is 12.27 MHz and convolution ops is 4*12.27 MHz. * * The depth has already been range checked before getting here and * the requested mode should have already been saved!! * * JMFBSetDepth is broken up into 8 main steps: * * 1. Range check the requested mode (should have been checked previously). * 2. Get a pointer to the right setup parameters as a f(depth) * 3. Setup CLUT. * 4. Setup clock generator chip if NTSC and convolved mode. * 5. Reset JMFB. * 6. Setup Stopwatch (timing generation). * 7. Start VRAM refresh. * 8. Start video transfers * * Called by: * * VidReset, SetVidMode * * Traps and Utilities called: * * _SwapMMUMode, GetClockType * * Register usage: * * Input: * D1 - depth mode, later used for other things * A3 - pointer to private storage, later used for other things * * Output: * None. * * Locally used: * D0 - scratch * D1 - scratch * D2 - used to fix A0 if we're NTSC convolved. (only mode that still has Natl) * A0 - pointer to hw setup parameters for requested mode. * A1 - pointer to hw control registers * A2 - pointer to the JMFB base (JMFB CSR) * A3 - holds a copy of the pointer to slot base addr * * Miscellaneous: * * 1. Note it is important that A3 be the pointer to driver private storage * prior to calling WaitVSync. * * 2. Since most monitor types have the same dot clock requirements across * all modes, it is redundant to resetup the clock each time that a mode * change occurs. The exception to this are the NTSC modes that are doing * convolution. In this mode a 49.08 MHz clock is used in 1,2,4, and 8 bit * modes, however a 12.27 MHz clock is used in 24 bpp mode (since we will * gracefully default to normal interlaced ops in that mode). To take * advantage of this space saving opportunity (~500 bytes), we must live * with 2 hardships. First we must fix the pointer to the hw setup params * if we're in the mode that has the extra data (convolution), since all * data blocks are assumed to be fixed in size and equal to the blocks that * don't have the National (or Endeavor) parameters. Second, we must * special case this mode out in the setup section, so we can adapt to the * different size hw setup blocks. * ******************************************************************* JMFBSetDepth MOVEM.L D0-D2/A0-A4,-(SP) ; save regs we are using CMP #Depth24BPP,D1 ; depth too big? BGT NoDepth ; =>yes, just exit MOVE.W csMode(A2),saveMode(A3) ; save mode number MOVE.L saveVidParms(A3),A0 ; get pointer to parms for this mode CMP #Depth1BPP,D1 ; test for 1 BPP mode BEQ.S @DoIt CMP #Depth2BPP,D1 ; test for 2 BPP mode BEQ.S @2BPP CMP #Depth4BPP,D1 ; test for 4 BPP mode BEQ.S @4BPP CMP #Depth8BPP,D1 ; test for 8 BPP mode BEQ.S @8BPP ADD.L #D_TFBP,A0 ; use 24 BPP parameters BRA.S @DoIt @8BPP ADD.L #D_EBP,A0 ; use 8 BPP parameters BRA.S @DoIt @4BPP ADD.L #D_FBP,A0 ; use 4 BPP parameters BRA.S @DoIt @2BPP ADD.L #D_TBP,A0 ; use 2 BPP parameters ; ; Initialize the hardware. ; @DoIt MOVEQ #true32b,D0 ; change to 32 bit addressing to get _SwapMMUMode ; at hardware MOVE D0,-(SP) ; save past addr mode for later MOVE.W SR,-(SP) ; get the current interrupt level MOVEQ.L #7,D0 ; setup to get interrupt level AND.B (SP),D0 ; D0 now holds current interrupt level SUBQ #2,D0 ; BGE.S @itsOK ; if >= 2 then intr level is ok ORI.W #$0200,SR ; if <2 then raise intr level to at least 2 ANDI.W #$FAFF,SR ; may have to drop it to 2 @itsOK BSR WaitVSync ; wait for vertical blanking BTST #ConvOnFlag,moreGFlags(A3) ; test to see if we're convoling or not BEQ.S @noKludge ; if we're not conv, then hw param size is ok MOVE.W saveMode(A3),D2 ; otherwise, adjust for additional clock params SUB #FirstVidMode,D2 ; make zero based MULU #D_ClockParams,D2 ; we are now using a universal ROM for Endeavor and Natl so use common param size ADD.L D2,A0 ; add to pointer to get to right table @noKludge MOVE.L saveHardBase(A3),A1 ; A1 <- slot base addr MOVE.W moreGFlags(A3),D2 ; save GFlags MOVE.L A3,A4 ; must save since it is passed to WaitVSync later MOVE.L A1,A3 ; A3 <- slot base addr ADD.L #CLUT+CLUTPBCR,A1 ; point to the CLUT Pixel Bus Control Register CLR.L D0 ; to ensure that the upper 2 bytes are 0 MOVE.W (A0)+,D0 ; setup the CLUT PBCR (data table field is word sized) MOVE.L D0,(A1) ; make a long write to hw always for this card MOVE.L A3,A1 ; get back to the slot base addr ADD.L #JMFB,A1 ; point to the base of the JMFB Registers MOVE.L A1,A2 ; save for later MOVE.W #2,D1 ; setup the 4 JMFB registers (the first one will be done outside the loop) CLR.L D0 ; to ensure that the upper 2 bytes are 0 MOVE.W (A0)+,D0 BTST #NationalFlag,moreGFlags(A4) ; all parameters are setup for National use so... BNE.S @writeOne ; if it's Natl, no need to do anything special ORI.W #PIXSEL1,D0 ; else it's Endeavor and we don't want to Reset (PIXSEL1=1) @writeOne MOVE.L D0,(A1)+ @part1 MOVE.W (A0)+,D0 ; do it (data table field is word sized) MOVE.L D0,(A1)+ ; make a long write to hw always for this card DBRA D1,@part1 MOVE.L A3,A1 ; get back to the slot base addr ADD.L #Endeavor,A1 ; point to the base of the Endeavor Registers BTST #ConvOnFlag,D2 ; test to see if we're convoling or not BEQ.S @skipPart2 BTST #NationalFlag,moreGFlags(A4) BNE.S @NatlSetup MOVE.W #2,D1 ; setup the 3 Endeavor registers CLR.L D0 ; to ensure that the upper 2 bytes are 0 @part2 MOVE.W (A0)+,D0 ; do it (data table field is word sized) MOVE.L D0,(A1)+ ; make a long write to hw always for this card DBRA D1,@part2 ADD.L #D_Natl,A0 BRA.S @skipPart2 @NatlSetup ADD.L #D_Endeavor,A0 MOVE.W #15,D1 ; setup the 16 National registers CLR.L D0 ; to ensure that the upper 3 bytes are 0 @part2a MOVE.B (A0)+,D0 ; do it (data table field is byte sized) MOVE.L D0,(A1)+ ; make a long write to hw always for this card DBRA D1,@part2a @skipPart2 ADD.L #JMFBCSR,A2 ; point to JMFB CSR BTST #NationalFlag,moreGFlags(A4) ; Are we National or Endeavor BNE.S @InitDelay ; if National, no need to reset Endeavor MOVE.L (A2),D1 ANDI.W #MaskSenseLine,D1 ; Ensure sense lines will be written out as 000 ORI.W #PIXSEL1,D1 ; set PIXSEL1 line to start Endeavor MOVE.L D1,(A2) @InitDelay MOVE.W #ShortDelay,D1 ; setup delay loop count @delayLoop DBRA D1,@delayLoop ; wait for stable clock from Endeavor MOVE.L (A2),D1 ANDI.W #MaskSenseLine,D1 ; Ensure sense lines will be written out as 000 ORI.W #VRSTB,D1 ; set VRSTB to start JMFB MOVE.L D1,(A2) MOVE.L A3,A1 ; get back to the slot base addr ADD.L #Stopwatch,A1 ; point to the base of the Stopwatch Registers MOVE.W #14,D1 ; setup next 15 registers (Stopwatch) CLR.L D0 ; to ensure that the upper 2 bytes are 0 @part3 MOVE.W (A0)+,D0 ; do it (data table field is word sized) MOVE.L D0,(A1)+ ; make a long write to hw always for this card DBRA D1,@part3 MOVE.L #$04,(A1) ; Always do a stopwatch soft reset MOVE.L #$05,(A1) ; Line interrupts off, Vertical Interrupts enabled and no soft reset MOVE.L (A2),D1 ANDI.W #MaskSenseLine,D1 ; Ensure sense lines will be written out as 000 ORI.W #REFEN,D1 ; set REFEN line to start VRAM refresh MOVE.L D1,(A2) MOVE.L A4,A3 ; restore A3 prior to calling WaitVSync BSR WaitVSync ; wait for one vertical blanking interval MOVE.L (A2),D1 ANDI.W #MaskSenseLine,D1 ; Ensure sense lines will be written out as 000 ORI.W #VIDGO,D1 ; set VRSTB line to start video transfer cycle MOVE.L D1,(A2) MOVE.W (SP)+,SR ; restore the interrupt level MOVE (SP)+,D0 ; restore past addr mode in D0 _SwapMMUMode NoDepth MOVEM.L (SP)+,D0-D2/A0-A4 ; restore all regs RTS ; return ******************************************************************* * * JMFBSetPage calculates the display base address from the mode and * page number. * * The base of a page is at saveHardBase(A3) + defmBaseOffset + (page * RowBytes * height) * * See the Miscellaneous section for special convolution and interlaced processing. * * JMFBSetPage is broken up into 6 main steps: * * 1. Get the rowbytes and screenrows from the misc. param. table * 2. Calculate base address (page num * rowbytes * screenrows) * 3. Call GetBaseOffset to get additional offset if any and add. * 4. If convolution blacken the phantom line (n-1) * 5. Fix the base address if we're a 24 bit sRsrc. * 6. Write to JMFB base address register. * * Called by: * * VidReset, SetVidMode * * Traps and Utilities called: * * SwapMMUMode * * Register usage: * * Input: * D1 - mode number * D4 - page number (zero based) * A1 - pointer to the AuxDCE * A3 - pointer to the private storage * * Output: * None. * * Locally used: * D2 - used to save rowbytes for mode * D3 - scratch * D4 - used to form the hardware base address for the JMFB CSR * D5 - used to hold the screen base address to go into privates * * Miscellaneous: * * There are three cases that require special consideration in the interlaced * modes. The first is when we are convolving and are in the underscan mode * (512x384). In this case we don't want to display the first active half * line in the active area. To do this we must place the qd base address * farther into the active area of the frame buffer as defined by the JMFB * base address. Specifically, we put the qd base address at $2000 (rowbytes * in interlaced mode always = $400), so the qd base address is 8 lines in * from the card base. Also, the JMFB base address must always be located * at the third row of a 4 row block due to hw design constraints for convolution * to work correctly (That means it can be a $c00, $1c00, $2c00, etc.). By * placing the qd base address at $2000 and the JMFB base addr at $c00, we * can eliminate the top half line artifact displayed in the active area of * the underscan mode.... confused yet...I almost am again and I wrote it! * Anyway, one last twist is that we'll blacken the entire frame buffer up * to the start of the screen base so we won't get any undesired artifacts * due to the 1:2:1 convolution kernal, at least not any unexpected artifacts! * The second case is a little more subtle since it is really done from the * GetBaseOffset utility. In 24 bpp we also want to get rid of the half line at * the top. There is a special base offset for 24 bpp ntsc that is #2560 (one * line into the frame buffer). By offseting qd 1 line past the JMFB base, se * should get rid of the half line in 24 bpp too!. The third case is similar * tho the 24 bpp case, but applies to indexed modes when there is only one * bank of vram and we are not convolving. In that case, the JMFB base addr * will be exactly 1 line (1024 bytes) behind qd. In this case and all indexed * cases, black is $FF. In 24 bpp (direct mode) black is $00. * ******************************************************************* JMFBSetPage MOVEM.L D0-D5/A0,-(SP) ; save all registers MOVE D4,savePage(A3) ; save the page MOVE saveMode(A3),D1 ; get the current "real" mode SUB #FirstVidMode,D1 ; make it 0 based MOVE.L saveVidParms(A3),A0 ; point to data table MOVE.W (D_RowBytes,A0,D1*2),D2 ; get and save rowBytes MULU D2,D4 ; calc page * rowBytes MULU D_Height(A0),D4 ; calc page * rowBytes * height BSR GetBaseOffset ; returns base offset in D0 ADD.L D0,D4 ; add the base offset to the page base MOVE.L D4,D5 ; save screen base offset for later to save in savebaseaddr MOVEQ #true32b,D0 ; change to 32 bit addressing to get _SwapMMUMode ; at hardware ; the following section gets pretty messy for ntsc modes to blacken the top of the fb and calc the JMFB baddr ; - case1 : indexed mode and convolving > qdBAddr = $2000, JMFB BAddr = $0C00, black = $FF ; - case2 : indexed mode and noConvolve > qdBAddr = $2000, JMFB BAddr = $1C00, black = $FF ; - case3 : 24 bpp > qdBAddr = #2560, JMFB BAddr = $0000, black = $00 ; ; what a mess! BTST #Interlaced,gFlags(A3) ; check for interlaced mode (1) for special processing BEQ.S @Continue ; use normal noninterlaced base offset value BTST #RAM512KFlag,gFlags(A3) ; check for 2nd bank of memory (0) BEQ.S @ConvOn ; can't do convolution w/o the 2nd bank SUB.L #OBM12CRB,D4 ; we're indexed and we can do this since all rowbytes are the same! BRA.S @BlackTop ; do the common blacktop stuff for indexed modes @ConvOn CMP.B #Mode8BPP,D1 ; test if mode is > 8 BPP BGT.S @ntsc24 ; can't do convolution in 24 BPP mode SUB.L #convBOfix,D4 ; form the magic JMFB base address (always $1400 less than screen base) @BlackTop MOVE.L saveHardBase(A3),A0 ; add the card base so we are now pointing to the line ADD.W #defmBaseOffset12,D2 ; get the number of bytes to blacken (from start of frame buffer to ; start of screen. LSR #2,D2 ; convert rowbytes to rowlongs SUBQ #1,D2 ; make it 0 based for the DBRA @NxtLong MOVE.L #$FFFFFFFF,(A0)+ ; write black for the entire phantom line DBF D2,@NxtLong BRA.S @Continue @ntsc24 SUB.L #TFBM12CRB,D4 ; JMFB base address is 1 line behind qd for 24 bpp MOVE.L saveHardBase(A3),A0 ADD.W #specBaseOffset12,D2 LSR #2,D2 SUBQ #1,D2 @aNxtLong MOVE.L #$00000000,(A0)+ ; write black for the entire phantom line ($00 for 24 bpp, $FF for indexed) DBF D2,@aNxtLong @Continue ADD.L saveHardBase(A3),D5 ; add base address for card BTST #sRsrc32Bit,GFlags(A3) ; check for 32 bit sRsrc (base address = Fsxx xxxx) BNE.S @saveIt ; if it is 32 bit sRsrc page base address is setup right BFEXTU D5{4,4},D3 ; else it's 24 bit (Fssx xxxx) so get slot number BFINS D3,D5{8,4} ; and insert it into D5 to form Fssx xxxx @saveit MOVE.L D5,saveBaseAddr(A3) ; return the base address ; Now set the hardware by writing the offset in longs to the proper registers. MOVE.L saveHardBase(A3),A0 ; get the card base addr ADD.L #JMFB,A0 ; point to JMFB Control Space ADD.L #JMFBVideoBase,A0 ; point to the Video Base register CMP.B #Mode8BPP,D1 ; test if mode is > 8 BPP. BLE.S @indexMode ; if 1,2,4, or 8 bpp we're all done so skip next instruction ASR.L #2,D4 ; it's 24 bpp, first /4 for pixel twist MULU.L #3,D4 ; multiply by 3 to finish the 3/4 pixel twist LSR.L #1,D4 ; one more /2 for interleaving @indexMode LSR.L #5,D4 ; strip lower 5 bits (bits 0:4 are implied 0) MOVE.L D4,(A0) ; base offset is the first register _SwapMMUMode MOVEM.L (SP)+,D0-D5/A0 ; restore all registers RTS ; and return ******************************************************************* * * GetBaseOffset returns the appropriate base address as a function of monitor and mode. There * are currently three alternatives: * * - defmBaseOffset - used for standard, and Rubik * - defmBaseOffsetBS - used for the Big Screens (Kong and Portrait) due to VRAM bank crossing * - defmBaseOffset12 - used for all overscan interlaced and convolved NTSC modes except 24 bpp. * - specBaseOffset12 - used in ntsc 24 bpp modes. * * GetBaseOffset is broken up into 3 main steps: * * 1. If small screen use defmBaseOffset * 2. If big screen use defmBaseOffsetBS * 3. If Interlaced use defmBaseOffset12 * * Called by: * * GetPageBase, JMFBSetPage * * Traps and Utilities called: * * None. * * Register usage: * * Input: * A3 - dCtlStorage pointer used to get at SaveMode, BigScreen, and Interlaced * * Output: ; D0 - returns the base offset value * * Locally used: ; None. * * Miscellaneous: * * None. * ******************************************************************* GetBaseOffset BTST #Interlaced,gFlags(A3) ; determine if it's NTSC or not BNE.S @Interlaced ; if it is branch and do the Interlaced modes BTST #BigScreen,gFlags(A3) ; determine if it's a Big Screen (Kong or Portrait) BEQ.S @SmallScreen ; if it is not then get the small screen base offset MOVE.L #defmBaseOffsetBS,D0 ; it's the Big Screen, so use defBaseOffsetBS BRA.S GBODone ; all done so get out @SmallScreen MOVE.L #defmBaseOffset,D0 ; it's the Small Screen, so use defBaseOffset BRA.S GBODone ; all done so get out @Interlaced CMP.W #FourthVidMode,saveMode(A3) ; check to see if we're greater than 8 bpp BGT.S @ntsc24bpp ; if > 8 bpp, we must be 24 so branch MOVE.L #defmBaseOffset12,D0 ; use the overscan NTSC base offset BRA.S GBODone ; all done so get out @ntsc24bpp MOVE.L #specBaseOffset12,D0 ; use a base offset that works for 24 bpp modes GBODone RTS ******************************************************************* * * GrayScreen writes a 50% gray dither pattern to the frame buffer. * The pattern used and the memory that is grayed is a f(mode). * * GrayScreen is broken up into 3 main steps: * * 1. Get the mode, the pattern, and the page size * 2. Form a 32 bit address in the fb pointer. * 3. Draw the screen (different code is used for 24 bpp than for indexed modes). * * Called by: * * VidReset, GrayPage * * Traps and Utilities called: * * _SwapMMUMode * * Register usage: * * Input: * A3 - pointer to the private storage * * Output: * None. * * Locally used: * D1 - scratch * D2 - used to hold rowlongs-1 * D3 - used to hold screenrows * D4 - used to hold rowbytes * D5 - 50% gray dither pattern (it's a f(mode)) * * A0 - points to the fb during writes * A1 - points to hw misc params * - later points to fb row starting addresses * * Miscellaneous: * * None. * ******************************************************************* GrayScreen MOVEM.L D0-D6/A0-A1,-(SP) ; save all registers MOVE saveMode(A3),D1 ; get the mode SUB #FirstVidMode,D1 ; make it 0 based MOVE.W D1,D3 ; make a copy of it LEA Pats,A1 ; get a pointer to the pattern table MOVE.L (A1,D3*4),D5 ; D5 = the proper pattern MOVE.L saveVidParms(A3),A1 ; point to data table MOVE (D_RowBytes,A1,D1*2),D4 ; D4 = rowbytes for the screen MOVE D_Height(A1),D3 ; D3 = screen height SUBQ #1,D3 ; make it 0 based MOVE.L saveBaseAddr(A3),A1 ; point to the current page BTST #sRsrc32Bit,GFlags(A3) ; Check to see if BNE.S @NoMask ; 32 bit address=1, 24 bit address=0 MOVE.L A1,D0 ; move into data register so we can and it ANDI.L #$FF0FFFFF,D0 ; Fssxxxxx -> Fs0xxxxx (since we always write in 32 bit addressing) MOVE.L D0,A1 ; move it back @NoMask MOVEQ #true32b,D0 ; draw in 32 bit mode _SwapMMUMode CMP.B #Mode24BPP,D1 ; check for 24 BPP mode BEQ.S gScrn24 ; do 24 bit gray screen in 24 BPP ; 1,2,4, and 8 BPP gray screen code NxtRow1 MOVE.L A1,A0 ; get next row MOVE.W D4,D2 ; get bytes per row LSR #2,D2 ; get longs per row MOVE.W D2,D7 ; save longs per row for later SUBQ #1,D2 ; make count 0 based NxtLong1 MOVE.L D5,(A0)+ ; write gray DBF D2,NxtLong1 ; for entire width of row NOT.L D5 ; get inverse gray for next row ADD.W D4,A1 ; bump to next row DBF D3,NxtRow1 ; until no more rows BTST #Interlaced,GFlags(A3) ; check to see if we're doing interlaced BEQ.S GSDone ; if we're not then all done BTST #UnderScanFlag,moreGFlags(A3) ; since we're doing interlaced, check for uScan BEQ.S GSDone ; if we're not uScan, then we're oScan and all done MOVE.W D7,D2 ; get longs per row BTST #PALFlag,moreGFlags(A3) BNE.S @PAL MULU.W #50,D2 ; multiply by scan lines +1 BRA.S @continue @PAL MULU.W #58,D2 @continue SUBQ #1,D2 ; make D2 0 based for dbra @BlackBot MOVE.L #-1,(A0)+ ; black out the bottom section DBRA D2,@BlackBot BRA.S GSDone ; 24 BPP gray screen code gScrn24 NxtRow24 MOVE.L A1,A0 ; get next row MOVE.W D4,D2 ; get bytes per row LSR #2,D2 ; get longs per row MOVE.W D2,D7 ; save longs per row for later SUBQ #1,D2 ; make count 0 based NxtLong24 MOVE.L D5,(A0)+ ; write gray NOT.L D5 ; invert next pixel for 24 BPP DBF D2,NxtLong24 ; for entire width of row NOT.L D5 ; invert for next row ADD.W D4,A1 ; bump to next row DBF D3,NxtRow24 ; until no more rows BTST #Interlaced,GFlags(A3) ; check to see if we're doing interlaced BEQ.S GSDone ; if we're not then all done BTST #UnderScanFlag,moreGFlags(A3) ; since we're doing interlaced, check for uScan BEQ.S GSDone ; if we're not uScan, then we're oScan and all done MOVE.W D7,D2 ; get longs per row BTST #PALFlag,moreGFlags(A3) BNE.S @PAL MULU.W #50,D2 ; multiply by scan lines +1 BRA.S @continue @PAL MULU.W #58,D2 @continue SUBQ #1,D2 ; make D2 0 based for dbra @BotBlack CLR.L (A0)+ ; black out the bottom section DBRA D2,@BotBlack GSDone _SwapMMUMode ; swap back to previous addr mode (do is still valid) MOVEM.L (SP)+,D0-D6/A0-A1 ; restore registers RTS ; and return Pats DC.L OneBitGray,TwoBitGray,FourBitGray,EightBitGray,TwentyFourBitGray ;------------------------------------------------------------- ; The Interrupt handler for Trident card ;------------------------------------------------------------- ; The interrupt Handler ; On entry A1 contains the pointer to the vsync clear register ; Note that the interrupt handler preserves D0-D3 and A0-A3. BeginIH MOVEM.L D1-D2/A0-A1,-(SP) ; save registers myself MOVEQ #true32b,D0 ; force to 32 bit addressing mode MOVE.L JSwapMMU,A0 ; call SwapMMUMode JSR (A0) MOVEM.L (SP)+,D1-D2/A0-A1 ; restore all registers MOVE.L D1,-(SP) ; save working register @waitNoVFP MOVE.L SWStatusReg-SWICReg(A1),D1 ; read the Stopwatch Status Register ANDI #$8,D1 ; wait for the Front Porch state to exit BNE.S @waitNoVFP ; continue to poll until we exit VFP (~90 usec) MOVE.L (SP)+,D1 MOVE.L #1,(A1) ; clear interrupt from card MOVEM.L D1-D2/A0-A1,-(SP) ; save registers MOVE.L JSwapMMU,A0 ; call SwapMMUMode JSR (A0) MOVEM.L (SP)+,D1-D2/A0-A1 ; restore all registers MOVE.L A1,D0 ; copy base addr into data register ; D0 = $Fssxxxxx ROL.L #8,D0 ; D0 <- $sxxxxxFs Convert the address into AND #$0F,D0 ; D0 <- $sxxx000s the slot number. MOVE.L JVBLTask,A0 ; call the VBL task manager JSR (A0) ; with slot # in D0 MOVEQ #1,D0 ; signal that int was serviced RTS ; and return to caller ;------------------------------------------------------------- ; TERROR ROM Support (for loading at GetDriver time) ;------------------------------------------------------------- If ForRom Then Export JMFBDrvrSize JMFBDrvrEnd JMFBDrvrSize Dc.l JMFBDrvrEnd-JMFBDrvr EndP Endif End