mirror of
https://github.com/elliotnunn/supermario.git
synced 2024-11-24 17:32:59 +00:00
1624 lines
62 KiB
Plaintext
1624 lines
62 KiB
Plaintext
;
|
||
; File: TFBDriver.a
|
||
;
|
||
; Contains: video driver for TFB card
|
||
;
|
||
; Written by: Ernie Beernik
|
||
;
|
||
; Copyright: © 1986-1992 by Apple Computer, Inc. All rights reserved.
|
||
;
|
||
; Change History (most recent first):
|
||
;
|
||
; <SM3> 11/3/92 SWC Changed SlotEqu.a->Slots.a and VideoEqu.a->Video.a.
|
||
; <SM2> 10/27/92 CSS Changed some short branches to word branches.
|
||
; <8> 8/21/91 JSM Clean up header.
|
||
; <7> 4/3/91 jmp TFB registers are byte wide, but the TFB reset register was
|
||
; being written to as a word. So, I changed a Move.w to a Move.b
|
||
; for TFBResetReg. This is coupled with a change in
|
||
; TFBDepVideoEqu.a where the TFBResetReg offset was incorrect (+3
|
||
; instead of -3).
|
||
; <6> 3/22/91 jmp Rolling the current TERROR ROM version of the TFBDriver into
|
||
; Reality due to a “screen tearing” problem occurring at
|
||
; SetEntries time. I introduced this problem when I was altering
|
||
; the TFBDriver for ’040 machines. Checked in with GM’s approval.
|
||
; <3> 2/10/91 jmp Rolled back to the original Reality sources (except for the
|
||
; byte-smearing an TERROR-ROM support additions) because of a
|
||
; “screen tearing” problem introduced by my screwing around with
|
||
; WaitVSync. Oops.
|
||
; <2> 1/6/91 jmp Cleaned up conditional assembly stuff (for ease of putting back
|
||
; into Reality).
|
||
; <1> 11/19/90 jmp Checking into TERROR ROM build for the first time.
|
||
; <5> 11/5/90 jmp Renamed DepVideoEqu.a to TFBDepVideoEqu.a; had to change INCLUDE
|
||
; name.
|
||
; <4> 11/2/90 jmp Most of the changes I made have been fixes for the TFB’s
|
||
; reliance on byte-smearing, which, of course, doesn't work on
|
||
; MC60840 machines. Specifically, I changed the Move.l’s in the
|
||
; WaitVSync routine to Move.b’s. I changed the Move.l in
|
||
; TFBSetDepth to Move.b. I simplified the GrayTable routine (i.e.,
|
||
; used a bigger DBra rather than 3 Moves per iteration). I removed
|
||
; the redundant interrupt-handling code that was occurring both
|
||
; before and inside of the calls to WaitVSync.
|
||
; <3> 1/4/90 DF Updated interrupt level changing code to reduce vsync wait
|
||
; overhead
|
||
; <2> 12/28/89 dba made it MAIN instead of PROC so we get dead code stripping
|
||
; <1.7> 11/27/89 DAF FOR 6.0.5: Fixed the major bug I created in 1.6. I allowed the
|
||
; bit depth rather than the mode spID to get passed to GrayPage.
|
||
; This is pretty deadly. This fix corrects the 1.6 bug AND the
|
||
; original bug report - that is, you don’t need to pass the mode
|
||
; spID to the GrayScreen control call. Updated version, too
|
||
; <1.6> 11/13/89 DAF For 6.0.5 and greater builds - Corrected some minor TFB driver
|
||
; bugs. Corrected GrayPage to use mode and page from registers
|
||
; (as it was originally intended). Corrected bug in GetEntries
|
||
; when in indexed mode.
|
||
; <1.5> 8/28/89 SES Removed references to nFiles.
|
||
; <1.4> 8/9/89 DAF Fixed a dereferencing problem in Status/GetPage. Stoopid...
|
||
; <1.4> 8/9/89 DAF FOR 6.0.4 BUILD - Fixed a dereferencing problem in
|
||
; Status/GetPage
|
||
; <1.3> 8/6/89 DAF Added some fixes to slot interrupt handling in the Open, Close,
|
||
; and SetInterrupt routines. Also improved error handling in Open
|
||
; <1.3> 8/5/89 DAF Updated Open, Close and interrupt routines to improve error and
|
||
; slot interrupt handler treatment.
|
||
; <1.2> 6/2/89 DAF Corrected dispatch range checking for Control call. Fixed a
|
||
; number of register problems in SetInterrupt. Thanks to Jay
|
||
; Zipnick for submitting these bugs.
|
||
; <1.2> 6/2/89 DAF Fixed a number of bugs in SetInterrupt, corrected control call
|
||
; range checking.
|
||
; <1.1> 5/2/89 DAF Numerous updates - Linear gamma, improved interrupt handling,
|
||
; internal gamma table format is no longer inverted, 3-channel
|
||
; gamma table component swap corrected
|
||
; <1.1> 5/2/89 DAF Fixed incorrect application of triple gamma tables in 8-bit
|
||
; sequence mode. Corrected interrupt disabling to be more friendly
|
||
; with F19 and Pink. Added linear gamma support. Updated version
|
||
; number. Fixed gamma table so that it's not inverted until used.
|
||
; <1.0> 11/16/88 CCH Added to EASE.
|
||
; <S461> 4/8/88 DAF Fixed a bug in the close call which caused an extra element to
|
||
; be placed in the slot interrupt queue. The bug was benevolent
|
||
; but it's better to fix this in the patch.
|
||
; <S441> 3/24/88 DAF Fixed GetGamma status call to move a long rather than word (!)
|
||
; <S406> 2/26/88 DAF Fixed a register trashing problem in the Status dispatcher
|
||
; <S306> 11/23/87 DAF Added SetInterrupt control call, GetGamma and GetInterrupt
|
||
; status calls, and updated version number
|
||
; <S237> 9/15/87 DAF Changed video driver name back to original
|
||
; <S190> 7/1/87 DAF Fixed GetEntries bug, added stack space check in SetEntries
|
||
; Corrected GetPageBase to use defMBaseOffset rather than a
|
||
; hardcoded value.
|
||
; <C843> 2/22/87 RDC Make version field word aligned
|
||
; <C827> 2/19/87 EHB Clear color table to gray before switching modes.
|
||
; <C839> 2/20/87 GWN Added version field to header.
|
||
; <C804> 2/12/87 DAF Added vRAM sizing, returns control error if 8-bit mode requested
|
||
; on 256K card.
|
||
; <C715> 1/28/87 GWN Made some code review changes.
|
||
; 1/25/87 EHB Changed mode table for 32 bit offset into RAM
|
||
; 1/21/87 EHB Fixed bug in sequence mode for 4 bits per pixel
|
||
; <C648> 1/16/87 EHB Universal TFB Driver for 1K and normal drivers
|
||
; <Cxxx> 1/8/87 EHB Added SetGray and GetGray calls for luminance mapping Allocate
|
||
; Ptr for gamma Table and store (inverted) gamma in ptr Do
|
||
; luminance mapping in SetEntries (index and sequence)
|
||
; <Cxxx> 12/26/86 EHB Do new setEntries mode as fast as possible.
|
||
; <Cxxx> 12/16/86 EHB Added multiple page support Added control call to clear screen
|
||
; <C535> 12/16/86 DAF Added SetGamma call
|
||
; <C522> 12/14/86 DAF Added gamma code, new setEntries mode, and shut off interrupts
|
||
; during setEntries
|
||
; <C497> 12/10/86 GWN Added Toby's code to sync depth change & Set entries. Removed
|
||
; DStartOpen flag. Modified Close so the interrupts are disabled
|
||
; and SQElement is removed.
|
||
; <C457> 11/23/86 EHB Added DStartOpen to header flags
|
||
; <C439> 11/18/86 GWN Modified DepthTbl.
|
||
; <C420> 11/18/86 RDC Added change to do setup of queue ID for _SIntInstall call
|
||
; <C389> 11/10/86 GWN Modified Get/Set Entries for DAF.
|
||
; <C371> 11/7/86 RDC Added fix to call jVBLTask instead of jCrsrTask
|
||
; <C336> 11/3/86 GWN Changed to new Video parameters as described in video card spec.
|
||
; (1,2,4 and 8-bit modes supported). Added mVertRefRate to video
|
||
; parameters. Changed to new SDM format header (ByteLanes field).
|
||
; Changed to 4-k ROM. Video driver is on ROM. Fixed video driver
|
||
; bugs: (1) SetEntries trash A0, (2) SetEntries/GetEntries Data
|
||
; NOT.;
|
||
; 10/21/86 GWN Changed Get & Set Entries to calculate the proper index for the
|
||
; hw dependent CLUT given a hw independent index. (for example:
|
||
; <0,1,2,3> => <$00,$40,$80,$C0>
|
||
; 10/16/86 GWN CLUT was not being set properly because Index to DepthTbl(D0)
|
||
; was calculated incorrectly.
|
||
; 10/15/86 GWN Added GetEntries to Get the CLUT.
|
||
; 10/13/86 GWN Added SetEntries to set the CLUT.
|
||
; 10/8/86 GWN Jump-table is now used for control and status csCode branches
|
||
; (CASE csCode OF).
|
||
; 10/7/86 GWN Made each module responsible for saving and restoring its local
|
||
; registers and data. Status now restores its registers instead of
|
||
; via control.
|
||
; 10/6/86 GWN 'Cleaned up' comments a bit.
|
||
; 10/2/86 GWN Modified Status calls for TFB card (Essentially copied from
|
||
; vidroutines.a).
|
||
; 9/22/86 GWN Modified control calls for TFB card (Essentially copied from
|
||
; vidroutines.a).
|
||
; 9/19/86 GWN Added interrupt handler instalation to open (Removed from
|
||
; primary init).
|
||
;
|
||
|
||
MACHINE MC68020
|
||
|
||
LOAD 'StandardEqu.d'
|
||
|
||
Print Off
|
||
INCLUDE 'ColorEqu.a'
|
||
INCLUDE 'Slots.a'
|
||
INCLUDE 'Video.a'
|
||
|
||
INCLUDE 'TFBDepVideoEqu.a'
|
||
Print On
|
||
|
||
If ForRom Then
|
||
TFBDrvr Proc Export
|
||
Else
|
||
VideoDrvr Main Export
|
||
Endif
|
||
|
||
;=====================================================================
|
||
; Local Vars, definitions, etc....
|
||
;=====================================================================
|
||
|
||
; This is device storage which is stored in the dCtlStorage field of the DCE.
|
||
|
||
DCEPtr EQU 0 ; pointer to our DCE
|
||
saveMode EQU DCEPtr+4 ; 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). <C497>
|
||
GammaPtr EQU saveSQElPtr+4 ; the pointer to the Gamma correction table <C522> DAF
|
||
GFlags EQU GammaPtr+4 ; flags word
|
||
VRAM256K EQU GFlags+2 ; boolean - TRUE if 256K vidRAM, FALSE if 512K <C804> DAF
|
||
dCtlSize EQU VRAM256K+2 ; size of dCtlStorage <C497>
|
||
|
||
; Flags within GFlags word
|
||
|
||
GrayFlag EQU 15 ; luminance mapped if GFlags(GrayFlag) = 1
|
||
IntDisFlag EQU 14 ; interrupts disabled if GFlags(IntFlag) =1
|
||
|
||
TFB1K EQU 0
|
||
|
||
;=====================================================================
|
||
; Video Driver Header
|
||
;=====================================================================
|
||
|
||
|
||
VidDrvr DC.W $4C00 ; ctl,status,needsLock <C497>
|
||
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_TFB' ; <PB237/15Sep87> DAF
|
||
STRING ASIS
|
||
ALIGN ; make sure we’re aligned <C843>
|
||
DC.W CurTFBDrvrVersion ; from TFBDepVideoEqu.a <jmp, 10/16/90>
|
||
|
||
;
|
||
**********************************************************************
|
||
*
|
||
* VideoOpen allocates private storage for the device in the DCE and locks
|
||
* it down for perpituity. Also, install the interrupt handler and enable
|
||
* the interrupts. <22Sep86> <22Sep86>
|
||
* It also sets the default gamma table included in the driver <C522> DAF
|
||
*
|
||
* Entry: A0 = param block pointer
|
||
* A1 = DCE pointer
|
||
*
|
||
* Locals: A2 = Saved param block pointer
|
||
* A3 = Saved DCE pointer
|
||
* A4 = Saved interrupt handler ptr.
|
||
*
|
||
**********************************************************************
|
||
|
||
; Save registers
|
||
|
||
WITH VDPageInfo,SlotIntQElement
|
||
VideoOpen MOVE.L A1,A3 ;A3 <- DCE pointer
|
||
|
||
; Allocate private storage.
|
||
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(A3) ; save returned handle in DCE
|
||
_HLock ; and lock it down
|
||
|
||
; get a pointer to private storage in A1 for the rest of Open
|
||
|
||
MOVE.L (A0),A1 ; <1.3>
|
||
|
||
; Get and install the interrupt handler. <19Sep86>
|
||
LEA BeginIH,A4 ;Save Pointer to interrupt handler. <C715>
|
||
MOVEQ #sqHDSize,D0 ;allocate a slot queue element
|
||
_NewPtr ,SYS,CLEAR ;get it from system heap cleared
|
||
BNE OpError1
|
||
|
||
MOVE.L A0,saveSQElPtr(A1) ; save pointer for later disposal <1.3>
|
||
|
||
MOVE.W #SIQType,SQType(A0) ;setup queue ID <C420>
|
||
MOVE.L A4,SQAddr(A0) ;setup int routine address
|
||
MOVE.L dctlDevBase(A3),SQParm(A0) ;save slot base addr as A3 parm
|
||
CLR.L D0
|
||
MOVE.B dctlSlot(A3),D0 ;setup slot #
|
||
_SIntInstall ;and do install
|
||
BNE.S OpError2
|
||
|
||
; SO DRIVER DOESN’T CARRY REDUNDANT GAMMA TABLE, INITIALIZE DRIVER WITH LINEAR GAMMA TABLE.
|
||
; Values in the gamma table are no longer inverted in place so that GetGamma will work correctly <1.1>
|
||
|
||
MOVEQ #0,D0 ; clear high word
|
||
MOVE #256+GFormulaData,D0 ; get size of gamma table
|
||
_NewPtr ,SYS,CLEAR ; allocate it in system heap
|
||
BNE.S OpError3 ; =>failed! return error
|
||
|
||
MOVE.L A0,GammaPtr(A1) ; else save off pointer
|
||
CLR.L (A0)+ ; version = 0, type = 0
|
||
MOVEQ #1,D0
|
||
MOVE.L D0,(A0)+ ; formula size = 0, channel counte = 1
|
||
MOVE.L #$01000008,(A0)+ ; 256 entries, 8 bits per entry
|
||
MOVE #$FF,D0 ; get count for dbra loop
|
||
@NxtEntry MOVE.B D0,D1 ; copy the index value <1.1>
|
||
NOT.B D1 ; invert it <1.1>
|
||
MOVE.B D1,(A0)+ ; set next byte <1.1>
|
||
DBRA D0,@NxtEntry ; repeat until done
|
||
|
||
; set luminance mapping and interrupts disabled to false <PB306/23Nov87> DAF
|
||
|
||
CLR GFlags(A1) ; set all flags false
|
||
|
||
;
|
||
; size video RAM and save boolean in private storage <C804/12Feb87> DAF
|
||
;
|
||
|
||
MOVE.L dctlDevBase(A3),A0 ;get base of vRAM
|
||
MOVE.L #TFBTestPos,D1 ;get offset in D1
|
||
MOVE.L #TFBTestPat,(A0,D1.L) ;write to alleged RAM
|
||
MOVE.L #-1,-(SP) ;write out some garbage to clear data lines
|
||
CLR.L (SP)+ ;and pitch it
|
||
MOVE.L (A0,D1.L),D0 ;read pattern back
|
||
CMP.L #TFBTestPat,D0 ;did it stick?
|
||
SNE VRAM256K(A1) ;mark boolean (A1 still has private storage ptr)
|
||
|
||
; Enable interrupts. <22Sep86>
|
||
|
||
ADD.L #ClrVInt,A0 ;bump to interrupt reg
|
||
CLR.B (A0) ;clear it.
|
||
|
||
MOVEQ #0,D0 ;no error
|
||
EndOpen RTS ;return
|
||
|
||
;
|
||
; Error handlers
|
||
;
|
||
OpError3 MOVE.L saveSQElPtr(A1),A0 ; get the slot queue element <1.3>
|
||
MOVEQ #0,D0 ; clear the register <1.3>
|
||
MOVE.B dCtlSlot(A3),D0 ; set the slot <1.3?
|
||
_sIntRemove ; remove the interrupt task <1.1>
|
||
OpError2 MOVE.L saveSQElPtr(A1),A0 ; get the slot queue block <1.3>
|
||
_DisposPtr ; release the slot queue block <1.3>
|
||
OpError1 MOVE.L dCtlStorage(A3),A0 ; get the private storage ptr <1.1>
|
||
_DisposHandle ; release the private storage <1.1>
|
||
OpError MOVE.L #OpenErr,D0 ; say can’t open driver <C715>
|
||
BRA.S EndOpen
|
||
|
||
|
||
|
||
|
||
**********************************************************************
|
||
*
|
||
* VideoClose releases the device’s private storage.
|
||
*
|
||
*
|
||
* Entry: A0 = param block pointer
|
||
* A1 = DCE pointer
|
||
*
|
||
**********************************************************************
|
||
|
||
VideoClose
|
||
|
||
MOVE.L dCtlDevBase(A1),A0 ;A0 <- base address of device <1.3>
|
||
ADD.L #DisableVInt,A0 ;Adjust the base <1.3>
|
||
CLR.B (A0) ;Disable interrupt from card <1.3>
|
||
|
||
MOVE.L dCtlStorage(A1),A2 ;Get pointer to private storage <1.3>
|
||
MOVE.L (A2),A2 ; <1.3>
|
||
MOVE.L saveSQElPtr(A2),A0 ;Get the SQ element pointer. <1.3>
|
||
MOVEQ #0,D0 ; clear out this register <1.2>
|
||
MOVE.B dCtlSlot(A1),D0 ;get the slot of the interrupt handler <S461>
|
||
_SIntRemove ;Remove the interrupt handler. <C497>
|
||
|
||
MOVE.L saveSQElPtr(A2),A0 ;dispose this queue element pointer <1.3>
|
||
_DisposPtr ; <1.3>
|
||
|
||
MOVE.L GammaPtr(A2),A0 ;get pointer to gamma table
|
||
_DisposPtr ;and dispose it
|
||
|
||
MOVE.L dCtlStorage(A1),A0 ;Dispose of the private storage. <C497>
|
||
_DisposHandle ; <C497>
|
||
|
||
MOVEQ #0,D0 ;get error into D0 <C715>
|
||
RTS ;return to caller
|
||
|
||
|
||
;
|
||
**********************************************************************
|
||
*
|
||
* Video Driver Control Call Handler. Right now there are six calls:
|
||
*
|
||
* (0) Reset (VAR mode, page: INTEGER; VAR BaseAddr: Ptr);
|
||
* (1) KillIO
|
||
* (2) SetMode(mode, page: INTEGER; VAR BaseAddr: Ptr);
|
||
* (3) SetEntries ( Table: Ptr; Start,Count : integer ); <C522/14Dec86> DAF
|
||
* (4) SetGamma ( Table : Ptr ); <C522/14Dec86> DAF
|
||
* (5) GrayPage (page); <EHB12/16>
|
||
* (6) SetGray (csMode = 0 for color, 1 for gray)
|
||
* (7) SetInterrupt (csMode = 0 to disable, 1 to enable) <S306/23Nov87> DAF
|
||
*
|
||
* Entry: A0 = param block pointer
|
||
* A1 = DCE pointer
|
||
* Uses: A2 = cs parameters (ie. A2 <- csParam(A0)) (must be preserved)
|
||
* A3 = scratch (doesn’t need to be preserved)
|
||
* A4 = scratch (must be preserved)
|
||
* D0-D3 = scratch (don’t need to be preserved)
|
||
*
|
||
* Exit: D0 = error code
|
||
*
|
||
**********************************************************************
|
||
|
||
; Decode the call
|
||
VideoCtl MOVEM.L A0/A4/D4,-(SP) ; save work registers (A0 is saved because it is used by ExitDrvr).
|
||
|
||
MOVE.W csCode(A0),D0 ; get the opCode
|
||
MOVE.L csParam(A0),A2 ; A2 <- Ptr to control parameters <22Sep86>
|
||
|
||
CMP.W #7,D0 ;IF csCode NOT IN [0..7] THEN <S306/23Nov87> DAF
|
||
BHI.S CtlBad ; Error, csCode out of bounds.
|
||
LSL.W #1,D0 ;Adjust csCode to be an index into the table.
|
||
MOVE.W CtlJumpTbl(PC,D0.W),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 <C522/14Dec86> DAF
|
||
DC.W GrayPage-CtlJumpTbl ;$05 => GrayPage <EHB12/16>
|
||
DC.W SetGray-CtlJumpTbl ;$06 => SetGray
|
||
DC.W SetInterrupt-CtlJumpTbl ;$07 => SetInterrupt <S306/22Nov87> DAF
|
||
|
||
SENoMem ADDQ #4,SP ; fix up the stack <S190> DAF
|
||
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 MOVEM.L (SP)+,A0/A4/D4 ; restore registers.
|
||
BRA ExitDrvr
|
||
|
||
|
||
|
||
VidReset
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; Reset the card to its default (one bit per pixel)
|
||
;
|
||
;---------------------------------------------------------------------
|
||
|
||
BSR TFBInit ; initialize the card <EHB12/16>
|
||
MOVE #OneBitMode,csMode(A2) ; return default mode <EHB12/16>
|
||
MOVE #1,D1 ; get depth in D1 <EHB12/16>
|
||
MOVEQ #0,D0 ; get page in D0 <EHB12/16>
|
||
MOVE D0,csPage(A2) ; return the page <EHB12/16>
|
||
MOVE.L dCtlStorage(A1),A3 ; get handle to our data <EHB12/16>
|
||
MOVE.L (A3),A3 ; A3 = our data <EHB12/16>
|
||
BSR TFBSetDepth ; set the depth from D1 <EHB12/16>
|
||
BSR TFBSetPage ; set the page from D0 <EHB12/16>
|
||
MOVE.L saveBaseAddr(A3),csBaseAddr(A2) ; return the base address <EHB12/16>
|
||
BSR GrayScreen ; paint the screen gray <EHB12/16>
|
||
BRA.S CtlGood ; => no error <EHB12/16>
|
||
|
||
|
||
|
||
SetVidMode
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; Set the card to the specified mode and page.
|
||
; If either is invalid, returns badMode error.
|
||
;
|
||
; If the card is already set to the specified mode, then do nothing.
|
||
;
|
||
; Note: Mode set is [1,2,4,8].
|
||
;
|
||
;---------------------------------------------------------------------
|
||
|
||
MOVE.W csMode(A2),D1 ; D1 = mode
|
||
BSR ChkMode ; get mode, check, map to depth (1, 2, 4 or 8) {D1 <- depth}
|
||
BNE.S CtlBad ; => not a valid mode
|
||
|
||
MOVE.W csPage(A2),D0 ; D0 = page
|
||
BSR ChkPage ; check page <EHB12/16>
|
||
BNE.S CtlBad ; => not a valid page <EHB12/16>
|
||
|
||
; Only set the mode if it has changed
|
||
; TFBSetDepth and TFBSetPage update the saved data in the dCtlStorage
|
||
|
||
SetEm
|
||
MOVE.L dCtlStorage(A1),A3 ; get handle to our data
|
||
MOVE.L (A3),A3 ; A3 = our data
|
||
MOVE.W csMode(A2),D2 ; D2 = mode <EHB12/17>
|
||
CMP saveMode(A3),D2 ; has the mode changed? <EHB12/17>
|
||
BEQ.S ModeOK1 ; => no, check the page <EHB12/16>
|
||
BSR.S GrayTable ; set color table to gray <C827>
|
||
BSR TFBSetDepth ; set the depth, get rowbytes <EHB12/16>
|
||
BSR TFBSetPage ; set the page <EHB12/16>
|
||
BRA.S NoChange ; => and return
|
||
|
||
ModeOK1 BSR TFBSetPage ; set the page <EHB12/16>
|
||
|
||
NoChange MOVE.L saveBaseAddr(A3),csBaseAddr(A2) ; return the base address <EHB12/16>
|
||
BRA.S CtlGood ; => return no error
|
||
|
||
|
||
GrayTable ; new routine <C827>
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; Jam the entire color table to gray before switching modes.
|
||
;
|
||
;---------------------------------------------------------------------
|
||
MOVEM.L A0-A1/D0-D1,-(SP) ; save registers
|
||
MOVE.W SR,-(SP) ; preserve the status register <2>
|
||
MOVEQ #7,D0 ; get mask in D0 <2>
|
||
AND.B (SP),D0 ; get the interrupt level <2>
|
||
SUBQ.B #2,D0 ; <2>
|
||
BGE.S @OK ; if ≥, then don't change <2>
|
||
ORI.W #$0200,SR ; raise above level-2 <2>
|
||
ANDI.W #$FAFF,SR ; make it level-2 <2>
|
||
@OK
|
||
BSR WaitVSync ; wait for next blanking period
|
||
|
||
MOVE.L dCtlStorage(A1),A0 ; get handle to private storage
|
||
MOVE.L (A0),A0 ; get pointer to storage (it’s locked!)
|
||
MOVE.L GammaPtr(A0),A0 ; get pointer to gamma data structure
|
||
MOVE GFormulaSize(A0),D0 ; get the size of formula data
|
||
LEA GFormulaData(A0),A0 ; point to formula data
|
||
ADD D0,A0 ; first correction table starts here
|
||
MOVE #$80,D1 ; get value for medium gray
|
||
MOVE.B (A0,D1),D1 ; get gamma corrected gray <1.1>
|
||
NOT.B D1 ; invert it <1.1>
|
||
|
||
MOVE.L dCtlDevBase(A1),A0 ; A0 <- base address of device.
|
||
ADD.L #ClrTbl+wCLUTDataReg,A0 ; add offset to color table data register
|
||
MOVE #$FF,D0 ; get count
|
||
@Repeat MOVE.B D1,(A0) ; PUT RED COMPONENT
|
||
MOVE.B D1,(A0) ; PUT GREEN COMPONENT
|
||
MOVE.B D1,(A0) ; PUT BLUE COMPONENT
|
||
DBRA D0,@Repeat ; UNTIL (entire table has been copied)
|
||
MOVE (SP)+,SR ; restore the status reg
|
||
MOVEM.L (SP)+,A0-A1/D0-D1 ; restore saved registers
|
||
RTS
|
||
|
||
|
||
SetEntries
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; Input :
|
||
; csParam -> datablock
|
||
; datablock = csTable -> table of colorSpecs (not colortable)
|
||
; csStart -> where to start setting, or -1
|
||
; csCount -> # of entries to change
|
||
;
|
||
; This call has two modes. In SEQUENCE mode, csCount entries are changed
|
||
; in the CLUT, starting at csStart. In INDEX mode, csCount entries are
|
||
; installed into the CLUT at the positions specified by their .value fields.
|
||
; This mode is selected by passing csStart = -1. In both cases, entries are
|
||
; range-checked to the dynamic range of the video mode (bits/pixel).
|
||
;
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; Set the CLUT.
|
||
; A0 = Ptr to the table.
|
||
; A1 = Ptr to DCE.
|
||
; A2 = Ptr to cs parameter record.
|
||
; A3 = Ptr to Vert sync state or Ptr to CLUT
|
||
; A4 = Ptr to gamma red table
|
||
; A5 = Ptr to gamma green table
|
||
; A6 = Ptr to gamma blue table
|
||
;
|
||
; D0-D4 = Scratch
|
||
; D5 = GRAY FLAG
|
||
; D6 = Index range [0..n].
|
||
; D7 = Shift constant (7,6,4 or 0).
|
||
;
|
||
;---------------------------------------------------------------------
|
||
|
||
; Initialize loop.
|
||
MOVE.L csTable(A2),D0 ; Check for a nil pointer.
|
||
BEQ CtlBad
|
||
|
||
MOVEM.L A5-A6/D5-D7,-(SP) ; save registers for gamma (A4/D4 saved by VideoCtl) <C522> DAF
|
||
MOVE.L dCtlStorage(A1),A0 ; get handle to private storage <C522> DAF
|
||
MOVE.L (A0),A0 ; get pointer to storage (it’s locked!) <C522> DAF
|
||
MOVE GFLAGS(A0),D5 ; KEEP FLAGS WORD IN D5
|
||
MOVE.L GammaPtr(A0),A0 ; get pointer to gamma data structure <C522> DAF
|
||
MOVE.W GFormulaSize(A0),D0 ; get the size of formula data <C522> DAF
|
||
LEA GFormulaData(A0),A4 ; point to formula data <C522> DAF
|
||
ADD D0,A4 ; red correction table starts here <C522> DAF
|
||
MOVE.L A4,A5 ; get default pointer to green data <C522> DAF
|
||
MOVE.L A4,A6 ; get default pointer to blue data <C522> DAF
|
||
CMP #1,GChanCnt(A0) ; if only only one table, we’re set <C522> DAF
|
||
BEQ.S OneTbl ; => just one table <C522> DAF
|
||
|
||
MOVE GDataCnt(A0),D0 ; get # entries in table <C522> DAF
|
||
MOVE GDataWidth(A0),D1 ; get width of each entry in bits
|
||
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 <C522> DAF
|
||
ADDA D0,A6 ; calc base of blue <C522> DAF
|
||
ADDA D0,A6 ; calc base of blue <C522> DAF
|
||
|
||
OneTbl SUB #16*8,SP ; make room for 16 entries <EHB>
|
||
|
||
; Get the index range (D6) and the shift constant (D7).
|
||
|
||
BSR CvtIndex
|
||
MOVE.L csTable(A2),A0 ; get colorSpec pointer in A0 <EHB>
|
||
|
||
; If it is sequence mode, then go do fast way
|
||
|
||
MOVE.W csStart(A2),D1 ; D1 = mode/start <C522> DAF
|
||
BMI.S NoSequence ; => not sequential <C522> DAF
|
||
CMP #255,D6 ; doing 256 entries?
|
||
BNE.S SLOSEQUENCE ; =>NO, NOT 8 BIT MODE <CXXX> EHB
|
||
CMP #4,csCount(A2) ; MORE THAN 4 ENTRIES? <CXXX> EHB
|
||
BGT SEQUENCE ; =>yes, fast special case
|
||
|
||
; For 4-bit and less, set up a color table on the stack that has indices
|
||
|
||
SloSequence MOVE.L SP,A3 ; point to stackSpecs <EHB>
|
||
MOVE csCount(A2),D0 ; get elements to copy <EHB>
|
||
|
||
@NxtSpec MOVE D1,(A3)+ ; copy index into stackSpec <EHB>
|
||
MOVE.L (A0)+,D2 ; get index, red <EHB>
|
||
MOVE D2,(A3)+ ; copy red <EHB>
|
||
MOVE.L (A0)+,(A3)+ ; copy green, blue <EHB>
|
||
ADDQ #1,D1 ; bump to next index <EHB>
|
||
DBRA D0,@NxtSpec ; => repeat for all specs <EHB>
|
||
|
||
MOVE.L SP,A0 ; get colorSpec pointer in A0 <EHB>
|
||
|
||
; disable cursor interrupts so that there will be time to change colors
|
||
; A0 already contains the pointer to colorSpecs
|
||
|
||
NoSequence
|
||
MOVE.W SR,-(SP) ; preserve status register <2>
|
||
MOVEQ #7,D0 ; get mask in D0 <2>
|
||
AND.B (SP),D0 ; get the interrupt level <2>
|
||
SUBQ.B #2,D0 ; <2>
|
||
BGE.S @OK ; if ≥, then don't change <2>
|
||
ORI.W #$0200,SR ; raise above level-2 <2>
|
||
ANDI.W #$FAFF,SR ; make it level-2 <2>
|
||
@OK
|
||
BSR WaitVSync ; wait for next blanking period (preserves A0)
|
||
|
||
; Copy the table to the CLUT
|
||
|
||
MOVE.W csCount(A2),D0 ; get the number of elements to change <C522> DAF
|
||
MOVE.L dCtlDevBase(A1),A3 ; A3 <- base address of device.
|
||
ADD.L #ClrTbl+wCLUTDataReg,A3 ; Add offset to color table data register <C522> DAF
|
||
|
||
@Repeat MOVE.L (A0)+,D2 ; GET INDEX, RED
|
||
SWAP D2 ; GET INDEX
|
||
MOVEQ #-1,D1 ; SET HIGH BITS FOR ROL.L
|
||
MOVE D2,D1 ; AND MOVE INTO D1
|
||
CMP.W D6,D1 ; IF D1 > MAXINDEX THEN
|
||
BHI.S @Until ; INDEX OUT OF RANGE
|
||
|
||
ROL.L D7,D1 ; CONVERT INDEX TO CLUT ENTRY
|
||
MOVE.B D1,wCLUTAddReg-wCLUTDataReg(A3) ; POINT TO CLUT ENTRY
|
||
|
||
SWAP D2 ; LEAVE RED IN D2
|
||
MOVE.L (A0)+,D3 ; GET GREEN,BLUE
|
||
MOVE.L D3,D4 ; GET BLUE IN D4.W
|
||
SWAP D3 ; GET GREEN IN D3.W
|
||
TST D5 ; TEST FLAGS WORD
|
||
BPL.S @NOGRAY ; =>DON’T DO LUMINANCE MAPPING
|
||
|
||
MULU #$4CCC,D2 ; MULTIPLY BY WEIGHT FOR RED
|
||
MULU #$970A,D3 ; MULTIPLY BY WEIGHT FOR GREEN
|
||
MULU #$1C28,D4 ; MULTIPLY BY WEIGHT FOR BLUE
|
||
ADD.L D3,D2 ; GET SUM OF RED, GREEN
|
||
ADD.L D4,D2 ; AND BLUE INTO D2
|
||
ROL.L #8,D2 ; GET HIGH BYTE AS LUMINANCE
|
||
AND #$00FF,D2 ; MAKE D2 A BYTE INDEX
|
||
MOVE.B (A4,D2),D2 ; get gamma corrected gray from red table <1.1>
|
||
NOT.B D2 ; invert it for hardware <1.1>
|
||
MOVE.B D2,(A3) ; PUT RED COMPONENT
|
||
MOVE.B D2,(A3) ; PUT GREEN COMPONENT
|
||
MOVE.B D2,(A3) ; PUT BLUE COMPONENT
|
||
DBRA D0,@Repeat ; UNTIL (entire table has been copied)
|
||
BRA.S @NOMORE ; => RETURN
|
||
|
||
@NOGRAY ROR #8,D2 ; GET HIGH BYTE OF RED
|
||
MOVEQ #0,D1 ; CLEAR OUT INDEX
|
||
MOVE.B D2,D1 ; AND GET BYTE INDEX
|
||
MOVE.B (A4,D1),D1 ; get gamma corrected red <1.1>
|
||
NOT.B D1 ; invert it for hardware <1.1>
|
||
MOVE.B D1,(A3) ; AND PUT TO CLUT
|
||
|
||
ROR #8,D3 ; GET HIGH BYTE OF GREEN
|
||
MOVEQ #0,D1 ; CLEAR OUT INDEX
|
||
MOVE.B D3,D1 ; AND GET BYTE INDEX
|
||
MOVE.B (A5,D1),D1 ; get gamma corrected green <1.1>
|
||
NOT.B D1 ; invert it for hardware <1.1>
|
||
MOVE.B D1,(A3) ; AND PUT TO CLUT
|
||
|
||
ROR #8,D4 ; GET HIGH BYTE OF BLUE
|
||
MOVEQ #0,D1 ; CLEAR OUT INDEX
|
||
MOVE.B D4,D1 ; AND GET BYTE INDEX
|
||
MOVE.B (A6,D1),D1 ; get gamma corrected blue <1.1>
|
||
NOT.B D1 ; invert it for hardware <1.1>
|
||
MOVE.B D1,(A3) ; AND PUT TO CLUT
|
||
|
||
@Until DBRA D0,@Repeat ; UNTIL (entire table has been copied)
|
||
|
||
@NOMORE MOVE.W (SP)+,SR ; restore the status reg <C522> DAF
|
||
ADD #16*8,SP ; strip stackSpecs
|
||
MOVEM.L (SP)+,A5/A6/D5-D7 ; restore saved registers <C522> DAF
|
||
|
||
BRA CtlGood ; => return no error
|
||
|
||
SEQUENCE
|
||
|
||
; make sure the stack is long aligned, and allocate buffer on stack
|
||
|
||
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
|
||
|
||
_StackSpace ; how much room is left on stack? <S190> DAF
|
||
CMP.L #$400+$100,D0 ; enough for 1024+256 slop? <S190> DAF
|
||
BLT SENoMem ; sorry, not enough <S190> DAF
|
||
|
||
SUB #$400,SP ; make room for 256*4 bytes
|
||
|
||
; build the color table on the stack
|
||
|
||
MOVE csStart(A2),D1 ; get the starting element
|
||
LEA 0(SP,D1*4),A3 ; A3 = pointer to first stack element
|
||
MOVE.W csCount(A2),D0 ; get the number of elements to change
|
||
MOVE.L csTable(A2),A0 ; get a pointer to the table of colorspecs
|
||
|
||
@Repeat CMP D6,D1 ; check index against max
|
||
BGT.S NoMore ; => oops, table is full
|
||
|
||
TST D5 ; TEST FLAGS WORD
|
||
BPL.S @NOGRAY ; =>DON’T DO LUMINANCE MAPPING
|
||
|
||
MOVE.L (A0)+,D2 ; GET RED IN D2.W
|
||
MOVE.W (A0)+,D3 ; GET GREEN IN D3.W
|
||
MOVE.W (A0)+,D4 ; GET BLUE IN D4.W
|
||
|
||
MULU #$4CCC,D2 ; MULTIPLY BY WEIGHT FOR RED
|
||
MULU #$970A,D3 ; MULTIPLY BY WEIGHT FOR GREEN
|
||
MULU #$1C28,D4 ; MULTIPLY BY WEIGHT FOR BLUE
|
||
ADD.L D3,D2 ; GET SUM OF RED, GREEN
|
||
ADD.L D4,D2 ; AND BLUE INTO D2
|
||
ROL.L #8,D2 ; GET HIGH BYTE AS LUMINANCE
|
||
MOVEQ #0,D3 ; CLEAR HIGH PART
|
||
MOVE.B D2,D3 ; copy the luminence
|
||
MOVE.B (A4,D3),D2 ; GET GAMMA CORRECTED GRAY
|
||
|
||
MOVE.B D2,D3 ; GET THE CORRECTED BLUE
|
||
LSL.L #8,D3 ; D3 = 00B0
|
||
MOVE.B D2,D3 ; D3 = 00BG
|
||
LSL.L #8,D3 ; D3 = 0BG0
|
||
MOVE.B D2,D3 ; D3 = 0BGR
|
||
MOVE.L D3,(A3)+ ; put blue, green, red to stack
|
||
ADDQ #1,D1 ; bump index
|
||
DBRA D0,@Repeat ; UNTIL (entire table has been copied)
|
||
BRA.S NOMORE ; => RETURN
|
||
|
||
@NOGRAY MOVEQ #0,D2 ; clear high part
|
||
MOVE.B rgb+blue(A0),D2 ; get blue
|
||
MOVE.B (A6,D2),D3 ; get the gamma corrected blue <1.1>
|
||
LSL.L #8,D3 ; D3 = xxBx
|
||
MOVE.B rgb+green(A0),D2 ; get green
|
||
MOVE.B (A5,D2),D3 ; get the gamma corrected green
|
||
LSL.L #8,D3 ; D3 = xBGx
|
||
MOVE.B rgb+red(A0),D2 ; get red
|
||
MOVE.B (A4,D2),D3 ; get the gamma corrected red (D3 = xBGR) <1.1>
|
||
MOVE.L D3,(A3)+ ; put blue, green, red to stack
|
||
|
||
ADDQ #1,D1 ; bump index
|
||
ADDQ #8,A0 ; point to next color spec
|
||
@Until DBRA D0,@Repeat ; UNTIL (entire table has been copied)
|
||
|
||
NoMore
|
||
MOVE.W SR,-(SP) ; preserve the status register <2>
|
||
MOVEQ #7,D0 ; get mask in D0 <2>
|
||
AND.B (SP),D0 ; get the interrupt level <2>
|
||
SUBQ.B #2,D0 ; <2>
|
||
BGE.S @OK ; if ≥, then don't change <2>
|
||
ORI.W #$0200,SR ; raise above level-2 <2>
|
||
ANDI.W #$FAFF,SR ; make it level-2 <2>
|
||
@OK
|
||
MOVE.L A3,A0 ; save pointer to last element inserted
|
||
|
||
BSR WaitVSync ; wait for vertical blanking
|
||
|
||
MOVE.L dCtlDevBase(A1),A3 ; A3 <- base address of device
|
||
ADD.L #ClrTbl,A3 ; bump to first control register
|
||
MOVEQ #0,D1 ; clear out D1
|
||
MOVE.B csStart+1(A2),D1 ; get the starting element to change
|
||
NOT.B D1 ; negate for position of starting element
|
||
MOVE.W csCount(A2),D0 ; get the number of elements to change
|
||
SUB.W D0,D1 ; calc first element to change
|
||
NOT.B D1 ; and negate for nubus
|
||
MOVE.B D1,wCLUTAddReg(A3) ; set address of first entry
|
||
|
||
ADD.L #wCLUTDataReg,A3 ; get address of data register
|
||
|
||
NextRGB MOVE.L -(A0),D1 ; get B,G,R
|
||
NOT.L D1 ; invert all three channels for hardware <1.1>
|
||
MOVE.B D1,(A3) ; set red
|
||
LSR.L #8,D1 ; get green
|
||
MOVE.B D1,(A3) ; set green
|
||
LSR.L #8,D1 ; get blue
|
||
MOVE.B D1,(A3) ; set green
|
||
DBRA D0,NextRGB ; => repeat for next RGB
|
||
|
||
MOVE.W (SP)+,SR ; restore the status reg <C522> DAF
|
||
ADD #$400,SP ; strip stack frame
|
||
MOVE.L (SP)+,SP ; restore stack alignment
|
||
ADD #16*8,SP ;
|
||
MOVEM.L (SP)+,A5/A6/D5-D7 ; restore saved registers <C522> DAF
|
||
|
||
BRA CtlGood ; => return no error
|
||
|
||
|
||
SetGamma ; <C522/15Dec86> DAF
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; Set the gamma table
|
||
; A0 = Ptr to private storage
|
||
; A1 = Ptr to DCE
|
||
; A2 = Ptr to cs parameter record
|
||
;
|
||
; If the csGTable parameter is NIL, then set the gamma table to be a linear
|
||
; gamma table. <1.1>
|
||
;
|
||
;---------------------------------------------------------------------
|
||
|
||
; get new gamma table and check that we know how to handle it
|
||
|
||
MOVE.L A1,-(SP) ; save DCE pointer
|
||
MOVE.L dCtlStorage(A1),A3 ; get handle to private storage
|
||
MOVE.L (A3),A3 ; get pointer to storage
|
||
|
||
MOVE.L csGTable(A2),D0 ; test for a NIL pointer
|
||
BEQ LinearTab ; if so, then this set up linear gamma
|
||
MOVE.L D0,A1 ; get pointer to new gamma table
|
||
|
||
TST.L GVersion(A1) ; version, type = 0?
|
||
BNE BadCtl ; => no, return error <SM2> CSS
|
||
CMP #8,GDataWidth(A1) ; is data width 8?
|
||
BNE BadCtl ; => no, return error <SM2> CSS
|
||
CMP #256,GDataCnt(A1) ; 256 values per channel?
|
||
BNE BadCtl ; => no, return error <SM2> CSS
|
||
|
||
; if new table is different size, reallocate memory
|
||
|
||
MOVE.L GammaPtr(A3),A0 ; get current gamma in A0
|
||
MOVE GFormulaSize(A1),D0 ; get size of formula in new
|
||
CMP GFormulaSize(A0),D0 ; same as current gamma table
|
||
BNE.S @GetNew ; =>no, resize pointer
|
||
MOVE GChanCnt(A1),D0 ; get number of tables in new
|
||
CMP GChanCnt(A0),D0 ; same as current gamma table?
|
||
BEQ.S @SizeOK ; => yes, data size ok
|
||
BGT.S @GetNew ; => new one is bigger, save old one
|
||
@NewSize _DisposPtr ; if new one smaller, dispose old one
|
||
CLR.L GammaPtr(A3) ; flag it’s been disposed
|
||
|
||
@GetNew MOVE #256,D0 ; get number of entries
|
||
MULU GChanCnt(A1),D0 ; multiply by number of tables
|
||
ADD GFormulaSize(A1),D0 ; add size of formula data
|
||
ADD #GFormulaData,D0 ; add gamma table header size
|
||
_NewPtr ,Sys ; and allocate a new pointer
|
||
BNE.S BadCtl ; => unable to allocate storage
|
||
|
||
MOVE.L GammaPtr(A3),D0 ; get old gamma table
|
||
MOVE.L A0,GammaPtr(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 GammaPtr(A3),A0 ; get new gamma table back
|
||
|
||
; copy the gamma table header
|
||
|
||
@SizeOK MOVE GChanCnt(A1),D0 ; get number of tables
|
||
MOVE GFormulaSize(A1),D1 ; get size of formula data
|
||
MOVE.L (A1)+,(A0)+ ; copy gamma header
|
||
MOVE.L (A1)+,(A0)+ ; which is
|
||
MOVE.L (A1)+,(A0)+ ; 12 bytes long ***
|
||
|
||
; copy the data
|
||
|
||
MOVE #256,D2 ; get number of entries
|
||
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 (A1)+,(A0)+ ; move a byte <1.1>
|
||
DBRA D2,@NxtByte ; => repeat for all bytes
|
||
|
||
Goody MOVE.L (SP)+,A1 ; restore DCE pointer
|
||
BRA CtlGood ; => return no error
|
||
|
||
BadCtl MOVE.L (SP)+,A1 ; restore DCE pointer
|
||
BRA CtlBad ; => return an error
|
||
|
||
|
||
;
|
||
; set up a linear gamma table. To prevent memory thrash, build this new one
|
||
; the same size as the existing one (one or three channel)
|
||
;
|
||
|
||
LinearTab
|
||
MOVE.L GammaPtr(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
|
||
BRA.S Goody ; all done
|
||
|
||
|
||
GrayPage ; <EHB12/16>
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; Clear the specified page in the current mode to gray
|
||
;
|
||
; A0 = Ptr to i/o parameter block
|
||
; A1 = Ptr to DCE
|
||
; A2 = Ptr to cs parameter record
|
||
;
|
||
;---------------------------------------------------------------------
|
||
|
||
MOVE.L dCtlStorage(A1),A3 ; get handle to our storage <EHB12/16>
|
||
MOVE.L (A3),A3 ; get pointer to our storage <EHB12/16>
|
||
MOVE saveMode(A3),D1 ; D1 = mode <EHB12/16>
|
||
BSR ChkMode ; convert mode to depth in D1 <EHB12/16>
|
||
BNE CtlBad ; => not a valid depth <C804/12Feb87> DAF
|
||
|
||
MOVE csPage(A2),D0 ; D0 = page <EHB12/16>
|
||
BSR ChkPage ; check page <EHB12/16>
|
||
BNE CtlBad ; => not a valid page <EHB12/16>
|
||
|
||
BSR GrayScreen ; paint the screen gray <EHB12/16>
|
||
|
||
BRA CtlGood ; => return no error <EHB12/16>
|
||
|
||
|
||
SetGray
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; Set luminance mapping on (csMode = 1) or off (csMode = 0)
|
||
;
|
||
; When luminance mapping is on, RGB values passed to setEntries are mapped
|
||
; to grayscale equivalents before they are written to the CLUT.
|
||
;
|
||
; A0 = Ptr to i/o parameter block
|
||
; A1 = Ptr to DCE
|
||
; A2 = Ptr to cs parameter record
|
||
;
|
||
;---------------------------------------------------------------------
|
||
|
||
MOVE.L dCtlStorage(A1),A3 ; get handle to our storage
|
||
MOVE.L (A3),A3 ; get pointer to our storage
|
||
MOVE GFlags(A3),D0 ; get current flags word
|
||
MOVE.B csMode(A2),D1 ; get boolean
|
||
BFINS D1,D0{16:1} ; set grayFlag
|
||
MOVE D0,GFlags(A3)
|
||
BRA CtlGood ; => return no error
|
||
|
||
|
||
SetInterrupt
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; Enable (csMode = 0) or disable (csMode = 1) VBL interrupts
|
||
;
|
||
; As a future performance enhancement, interrupts on the card can be
|
||
; disabled or enabled from software. For instance, if the cursor is
|
||
; not on a screen, and there is nothing in the Slot Interrupt Queue
|
||
; for that device, interrupts may be disabled reducing interrupt
|
||
; overhead for the system.
|
||
;
|
||
; The EnableThem routine is updated to NOT allocate memory when called.
|
||
; Now, it reuses the sqElement that was created in Open. This allows this
|
||
; routine to be called at interrupt time, and fixes the unbalanced memory
|
||
; allocation problems from before.
|
||
;
|
||
; A0 = Ptr to i/o parameter block
|
||
; A1 = Ptr to DCE
|
||
; A2 = Ptr to cs parameter record
|
||
;
|
||
;---------------------------------------------------------------------
|
||
|
||
WITH VDPageInfo,SlotIntQElement
|
||
|
||
MOVE.L dCtlStorage(A1),A3 ; get handle to our storage
|
||
MOVE.L (A3),A3 ; get pointer to our storage
|
||
MOVE GFlags(A3),D0 ; get current flags word
|
||
MOVE.B csMode(A2),D1 ; get boolean
|
||
BFINS D1,D0{17:1} ; set IntFlag
|
||
MOVE D0,GFlags(A3) ; put flag word back
|
||
|
||
BTST #IntDisFlag,D0 ; is the flag on or off?
|
||
BEQ.S EnableThem ; if zero, then enable
|
||
|
||
; this code disables VBL interrupts, then removes the interrupt handler
|
||
|
||
BSR WaitVSync ; to be safe, wait for the next VBL
|
||
MOVE.L dCtlDevBase(A1),A0 ; get the device base <1.2>
|
||
ADD.L #DisableVInt,A0 ; point to hardware register <1.2>
|
||
CLR.B (A0) ; hit the register
|
||
|
||
MOVE.L saveSQElPtr(A3),A0 ; get the SQ element pointer <1.2>
|
||
MOVEQ #0,D0 ; clear D0 out <1.2>
|
||
MOVE.B dCtlSlot(A1),D0 ; set up slot number <1.2>
|
||
_SIntRemove ; remove the interrupt handler
|
||
BRA CtlGood ; done
|
||
|
||
EnableThem
|
||
MOVE.L saveSQElPtr(A3),A0 ; get pointer to slot queue element <1.3>
|
||
LEA BeginIH,A4 ; save Pointer to interrupt handler
|
||
MOVE.W #SIQType,SQType(A0) ; setup queue ID
|
||
MOVE.L A4,SQAddr(A0) ; setup int routine address
|
||
MOVE.L dctlDevBase(A1),SQParm(A0) ; save slot base addr as A3 parm
|
||
CLR.L D0
|
||
MOVE.B dctlSlot(A1),D0 ; setup slot #
|
||
_SIntInstall ; and do install
|
||
BNE CtlBad
|
||
|
||
MOVE.L dctlDevBase(A1),A0 ; get hardware base
|
||
ADD.L #ClrVInt,A0 ; hit the clear register (which also enables)
|
||
CLR.B (A0) ; start interrupts happening
|
||
|
||
BRA CtlGood ; and go home
|
||
|
||
ENDWITH
|
||
|
||
;
|
||
**********************************************************************
|
||
*
|
||
* Video Driver Status Call Handler. Right now there are eight calls:
|
||
*
|
||
* (0) Error
|
||
* (1) Error
|
||
* (2) GetMode
|
||
* (3) GetEntries
|
||
* (4) GetPage
|
||
* (5) GetPageBase
|
||
* (6) GetGray
|
||
* (7) GetInterrupt <S306/23Nov87> DAF
|
||
* (8) GetGamma <S306/23Nov87> DAF
|
||
*
|
||
* Entry: A0 = param block
|
||
* A1 = DCE pointer
|
||
* Uses: A2 = cs parameters (ie. A2 <- csParam(A0)) (must be preserved)
|
||
* A3 = scratch (doesn’t need to be preserved)
|
||
* D0-D3 = scratch (don’t need to be preserved)
|
||
*
|
||
* Exit: D0 = error code
|
||
*
|
||
**********************************************************************
|
||
|
||
VideoStatus
|
||
MOVE.L A0,-(SP) ; save a register <S406/26Feb88> DAF
|
||
MOVE.W csCode(A0),D0 ; get the opCode
|
||
MOVE.L csParam(A0),A2 ; A2 <- Ptr to control parameters <22Sep86>
|
||
|
||
|
||
CMP.W #8,D0 ;IF csCode NOT IN [0..8] 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
|
||
|
||
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 saved register <S406/26Feb88> DAF
|
||
BRA ExitDrvr
|
||
|
||
|
||
GetMode
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; Return the current mode
|
||
;
|
||
;---------------------------------------------------------------------
|
||
|
||
MOVE.L dCtlStorage(A1),A3 ; get handle to our storage
|
||
MOVE.L (A3),A3 ; get pointer to our storage
|
||
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
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; Get the CLUT.
|
||
;
|
||
;---------------------------------------------------------------------
|
||
|
||
; Initialize loop.
|
||
MOVE.L csTable(A2),D0 ; Check for a nil pointer.
|
||
BEQ.S StatBad
|
||
MOVE.L D0,A0 ; A0 <- pointer to table.
|
||
|
||
MOVE.W csCount(A2),D0 ; get the count <1.6/DAF>
|
||
|
||
CMP.W #-1,csStart(A2) ; is it index or sequence mode? <C5??/04Jan87> DAF
|
||
BEQ.S GECom ; if index, then continue <C5??/04Jan87> DAF
|
||
|
||
MOVE.W D0,D1 ; make a copy for index loop <S190/01Jul87> DAF
|
||
MOVE.W D0,D2 ; make a copy of the count <C5??/04Jan87> DAF
|
||
ADD.W csStart(A2),D2 ; get last index <C5??/04Jan87> DAF
|
||
@1
|
||
MOVE.W D2,value(A0,D1*8) ; write the index into the table <C5??/04Jan87> DAF
|
||
SUBQ #1,D2 ; decrease index
|
||
DBRA D1,@1 ; for all indices <C5??/04Jan87> DAF
|
||
|
||
GECom
|
||
|
||
MOVEM.L D6-D7,-(SP) ; SAVE WORK REGISTERS
|
||
|
||
; Get the index range (D6) and the shift constant (D7).
|
||
BSR CvtIndex
|
||
|
||
; Copy the CLUT to the Table
|
||
|
||
MOVE.L dCtlDevBase(A1),A3 ; A3 <- base address of device.
|
||
ADD.L #ClrTbl,A3 ; Add offset to color regs.
|
||
|
||
; REPEAT
|
||
@Repeat MOVE.W value(A0),D1 ; D1 <- xindex.
|
||
CMP.W D6,D1 ; IF D1 > D6 THEN
|
||
BHI.S @Until ; GOTO @Until {Index is out of range for this mode}
|
||
|
||
OR.L #$FFFF0000,D1 ; get ones in hi half of d1.<C389/10Nov86>
|
||
ROL.L D7,D1 ; shift it. <C389/10Nov86>
|
||
|
||
MOVE.B D1,wCLUTAddReg(A3) ; Point to proper entry in CLUT
|
||
|
||
MOVE.B rCLUTDataReg(A3),D1 ; Get red
|
||
NOT.W D1
|
||
MOVE.B D1,rgb+red(A0)
|
||
MOVE.B D1,rgb+red+1(A0) ; <C715>
|
||
|
||
MOVE.B rCLUTDataReg(A3),D1 ; Get green
|
||
NOT.W D1
|
||
MOVE.B D1,rgb+green(A0)
|
||
MOVE.B D1,rgb+green+1(A0) ; <C715>
|
||
|
||
MOVE.B rCLUTDataReg(A3),D1 ; Get blue
|
||
NOT.W D1
|
||
MOVE.B D1,rgb+blue(A0)
|
||
MOVE.B D1,rgb+blue+1(A0) ; <C715>
|
||
|
||
@Until ADDQ.L #colorSpecSize,A0 ; A0 <- next entry in the table.
|
||
DBRA D0,@Repeat ; UNTIL (entire table has been copied)
|
||
|
||
MOVEM.L (SP)+,D6-D7 ; RESTORE WORK REGISTERS
|
||
|
||
BRA StatGood ; => return no error
|
||
|
||
|
||
|
||
|
||
GetPage
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; Return the number of pages in the specified mode
|
||
;
|
||
;---------------------------------------------------------------------
|
||
|
||
MOVE csMode(A2),D1 ; get the mode <EHB12/16>
|
||
BSR ChkMode ; check mode, get depth in D1 <EHB12/16>
|
||
BNE StatBad ; => not a valid mode <EHB12/16>
|
||
|
||
MOVE.L dCtlStorage(A1),A0 ; get private storage handle <C804/12Feb87> DAF
|
||
MOVE.L (A0),A0 ; get pointer <1.3/DAF>
|
||
TST.B VRAM256K(A0) ; 512K or 256K? <C804/12Feb87> DAF
|
||
BNE.S @1 ; if TRUE, then 256K of RAM <C804/12Feb87> DAF
|
||
MOVEQ #4,D0 ; if FALSE, 512K vRAM (and 1 more page per mode) <C804/12Feb87> DAF
|
||
BRA.S @2
|
||
@1 MOVEQ #3,D0 ; get one-bit page count <EHB12/16>
|
||
@2 DIVU D1,D0 ; divide by depth <EHB12/17>
|
||
ADD #1,D0 ; make it one based <EHB12/17>
|
||
MOVE D0,csPage(A2) ; return page count <EHB12/16>
|
||
BRA StatGood ; => return no error <EHB12/16>
|
||
|
||
|
||
|
||
GetPageBase
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; Return the base address for the specified page in the current mode
|
||
;
|
||
;---------------------------------------------------------------------
|
||
|
||
MOVE.L dCtlStorage(A1),A3 ; get handle to our storage <EHB12/16>
|
||
MOVE.L (A3),A3 ; get pointer to our storage <EHB12/16>
|
||
MOVE saveMode(A3),D1 ; get the current mode <EHB12/16>
|
||
BSR ChkMode ; convert to depth in D1 <EHB12/16>
|
||
MOVE.W csPage(A2),D0 ; get the requested page <EHB12/16>
|
||
BSR ChkPage ; is the page valid? <EHB12/16>
|
||
BNE StatBad ; => no, just return <EHB12/16>
|
||
|
||
MOVE saveMode(A3),D1 ; get the current mode <EHB12/16>
|
||
SUB #OneBitMode,D1 ; make it 0 based <EHB12/17>
|
||
LEA ModeTbl,A0 ; point to tables <EHB12/16>
|
||
MULU 4(A0,D1*8),D0 ; calc page * rowBytes <EHB12/16>
|
||
MULU 6(A0,D1*8),D0 ; calc page * rowBytes * height <EHB12/16>
|
||
MOVEQ #defmBaseOffset,D1 ; add offset for TFB <EHB12/16>
|
||
ADD.L D1,D0 ; which doesn’t use first long <EHB12/16>
|
||
ADD.L dCtlDevBase(A1),D0 ; add base address for card <EHB12/17>
|
||
MOVE.L D0,csBaseAddr(A2) ; return the base address <EHB12/16>
|
||
|
||
BRA StatGood ; => return no error
|
||
|
||
|
||
GetGray
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; Return a boolean, set true if luminance mapping is on
|
||
;
|
||
;---------------------------------------------------------------------
|
||
|
||
CLR csMode(A2) ; assume that grayFlag is false
|
||
MOVE.L dCtlStorage(A1),A3 ; get handle to our storage
|
||
MOVE.L (A3),A3 ; get pointer to our storage
|
||
TST GFlags(A3) ; is luminance mapping on?
|
||
BPL StatGood ; => no, return false
|
||
MOVE.B #1,csMode(A2) ; else return true
|
||
BRA StatGood ; => and return
|
||
|
||
|
||
GetInterrupt
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; Return a boolean in csMode, set true if VBL interrupts are disabled
|
||
;
|
||
;---------------------------------------------------------------------
|
||
|
||
CLR csMode(A2) ; assume that grayFlag is false
|
||
MOVE.L dCtlStorage(A1),A3 ; get handle to our storage
|
||
MOVE.L (A3),A3 ; get pointer to our storage
|
||
BTST #IntDisFlag,GFlags(A3) ; is luminance mapping on?
|
||
BEQ StatGood ; => no, return false
|
||
MOVE.B #1,csMode(A2) ; else return true
|
||
BRA StatGood ; => and return
|
||
|
||
|
||
GetGamma
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; Return the handle to the current gamma table
|
||
;
|
||
;---------------------------------------------------------------------
|
||
|
||
MOVE.L dCtlStorage(A1),A3 ; get handle to our storage
|
||
MOVE.L (A3),A3 ; get pointer to our storage
|
||
MOVE.L GammaPtr(A3),csGTable(A2) ; return the pointer to the structure <S441>
|
||
BRA StatGood ; and return a good result
|
||
|
||
|
||
;=====================================================================
|
||
;
|
||
; Special.
|
||
;
|
||
;=====================================================================
|
||
|
||
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; Wait for vertical blanking
|
||
;
|
||
; A1 = DCE POINTER
|
||
;---------------------------------------------------------------------
|
||
|
||
WaitVSync
|
||
Move.l A0,-(Sp) ; Two Moves are faster than a Movem for
|
||
Move.l D0,-(Sp) ; two registers.
|
||
|
||
MOVE.W SR,-(SP) ; preserve the status register <2>
|
||
MOVEQ #7,D0 ; get mask in D0 <2>
|
||
AND.B (SP),D0 ; get the interrupt level <2>
|
||
SUBQ.B #2,D0 ; <2>
|
||
BGE.S @OK ; if ≥, then don't change <2>
|
||
ORI.W #$0200,SR ; raise above level-2 <2>
|
||
ANDI.W #$FAFF,SR ; make it level-2 <2>
|
||
@OK
|
||
MOVE.L dctlDevBase(A1),A0 ;A3 <- slot base addr <C497>
|
||
ADD.L #RdVSync,A0 ;Adjust base addr <C497>
|
||
@0 MOVE.B (A0),D0 ;Read the Vert-Sync state, <C497><jmp>: .L to .B
|
||
BTST #0,D0 ; and test it. <C497>
|
||
BNE.S @0 ;Repeat until it goes low. <C497>
|
||
; <C497>
|
||
@1 MOVE.B (A0),D0 ;Read the Vert-Sync state, <C497><jmp>: .L to .B
|
||
BTST #0,D0 ; and test it. <C497>
|
||
BEQ.S @1 ;Repeat until it goes high. <C497>
|
||
|
||
MOVE (SP)+,SR ;RE-ENABLE CURSOR INTERRUPTS
|
||
Move.l (Sp)+,D0 ; Restore work registers.
|
||
Move.l (Sp)+,A0
|
||
|
||
RTS
|
||
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; 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
|
||
;
|
||
;=====================================================================
|
||
|
||
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; CvtIndex
|
||
;
|
||
; Calculate the proper index for the hw dependent CLUT given a
|
||
; hw independent index. (for example: <0,1,2,3> => <$00,$40,$80,$C0>
|
||
;
|
||
; -> A1 : Ptr to the DCE.
|
||
; <- D6 : The Index Range (1,3,15 or 255).
|
||
; <- D7 : The Shift Constant (7,6,4 or 0).
|
||
;
|
||
;---------------------------------------------------------------------
|
||
|
||
; Save registers
|
||
CvtIndex MOVEM.L A3/D0/D4,-(SP) ; Save registers
|
||
|
||
; Get the mode (D4). mode will be 1,2,4 or 8.
|
||
MOVE.L dCtlStorage(A1),A3 ; D7 <- the mode (onebitmode, twobitmode,....)
|
||
MOVE.L (A3),A3
|
||
MOVE.W saveMode(A3),D7
|
||
SUB.W #OneBitMode,D7 ; D7 <- (0,1,2 or 3)
|
||
MOVEQ #1,D4 ; D4 <- 1 << D3 {ie. 1,2,4 or 8}
|
||
LSL.W D7,D4
|
||
|
||
; Determine the index range (D6). Range will be in [0..n], we need to calculate n.
|
||
MOVE.W D4,D0 ; D0 <- (0,1,3 or 7)
|
||
SUBQ #1,D0
|
||
MOVEQ #2,D6 ; D6 <- (2 << D0) - 1 {ie. 1,3,15,255}
|
||
LSL.W D0,D6
|
||
SUBQ #1,D6
|
||
|
||
; Determine the shift constant (D7). SC = (7,6,4 or 0).
|
||
MOVEQ #8,D7 ; D7 <- (7,6,4 or 0)
|
||
SUB.W D4,D7
|
||
|
||
; End
|
||
MOVEM.L (SP)+,A3/D0/D4 ; Restore registers
|
||
RTS
|
||
|
||
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; ChkMode
|
||
;
|
||
; Maps the mode to a depth (1, 2, 4 or 8)
|
||
; Assumes DCE pointer in A1.
|
||
;
|
||
; -> D1: Mode
|
||
; <- D1: Depth
|
||
; D0: trashed
|
||
;
|
||
; Returns EQ if mode is valid.
|
||
|
||
ChkMode SUB #OneBitMode,D1 ; make it 0 based
|
||
BMI.S ModeBad ; =>bad mode, return
|
||
|
||
CMP #3,D1 ; is it too big?
|
||
BGT.S ModeBad ; =>yes, return
|
||
|
||
MOVEQ #1,D0 ; get a one
|
||
LSL D1,D0 ; convert to a depth
|
||
MOVE D0,D1 ; and return in D1
|
||
|
||
CMP.W #8,D1 ; requesting 8-Bit mode? <C804/12Feb87> DAF
|
||
BNE.S @1 ; 1,2,4 always OK <C804/12Feb87> DAF
|
||
MOVE.L A0,-(SP) ; save A0 <C804/12Feb87> DAF
|
||
MOVE.L dCtlStorage(A1),A0 ; get handle to private storage <C804/12Feb87> DAF
|
||
MOVE.L (A0),A0 ; get pointer to private storage <C804/12Feb87> DAF
|
||
TST.B VRAM256K(A0) ; is there too little RAM? <C804/12Feb87> DAF
|
||
MOVE.L (SP)+,A0 ; restore register <C804/12Feb87> DAF
|
||
BNE.S ModeBad ; if TRUE, then return error <C804/12Feb87> DAF
|
||
@1
|
||
|
||
ModeOK CMP.W D1,D1 ; get EQ
|
||
ModeBad RTS ; EQ if valid depth
|
||
|
||
|
||
;---------------------------------------------------------------------
|
||
;
|
||
; ChkPage
|
||
;
|
||
; Checks to see if the page in D0 is valid for the depth in D1.
|
||
; Max page numbers are 4 for 1 bit mode; 2 for 2 bit mode; 1 for 4 bit mode;
|
||
; and 0 for 8 bit mode.
|
||
; Assumes DCE pointer in A1.
|
||
;
|
||
; -> D0: Page
|
||
; -> D1: Depth
|
||
;
|
||
; Returns EQ if page is valid.
|
||
|
||
ChkPage MOVEM.L D2/A0,-(SP) ; save work registers <EHB12/17><C804/12Feb87> DAF
|
||
MOVE.L dCtlStorage(A1),A0 ; get private storage handle <C804/12Feb87> DAF
|
||
MOVE.L (A0),A0 ; get pointer to private storage <C804/12Feb87> DAF
|
||
TST.B VRAM256K(A0) ; 512K or 256K? <C804/12Feb87> DAF
|
||
BNE.S @1 ; if TRUE, then 256K of RAM <C804/12Feb87> DAF
|
||
MOVEQ #4,D2 ; if FALSE, 512K vRAM (and 1 more page per mode) <C804/12Feb87> DAF
|
||
BRA.S @2
|
||
@1 MOVEQ #3,D2 ; get max one bit page count <EHB12/17>
|
||
@2 DIVU D1,D2 ; divide by depth <EHB12/17>
|
||
CMP D2,D0 ; is page # too big? <EHB12/17>
|
||
SGT D2 ; set flag if too big <EHB12/16>
|
||
TST.B D2 ; and test condition <EHB12/16>
|
||
MOVEM.L (SP)+,D2/A0 ; restore work registers <EHB12/16>
|
||
RTS
|
||
|
||
|
||
;---------------------------------------------------------------------
|
||
; InitTFB initializes the TFB
|
||
; All Registers preserved
|
||
;---------------------------------------------------------------------
|
||
|
||
TFBInit MOVEM.L D0/A0/A1,-(SP) ;save all regs
|
||
|
||
MOVE.L dctlDevBase(A1),A0 ;A0 <- slot base addr
|
||
ADD.L #TFBIBase,A0 ;point to registers
|
||
LEA TFBInitTbl,A1 ;get data pointer
|
||
|
||
MOVEQ #$F,D0 ;do 16 bytes
|
||
@0 MOVE.B (A1)+,(A0) ;set one byte
|
||
SUBQ #4,A0 ;back up to prev register
|
||
DBRA D0,@0 ;repeat until done
|
||
|
||
MOVEM.L (SP)+,D0/A0/A1 ;restore all regs
|
||
RTS ;init done
|
||
|
||
|
||
TFBInitTbl DC.B $DF,$B8,$FF,$FF,$E1,$1A,$88,$B9
|
||
DC.B $FA,$FD,$FD,$FE,$F0,$BE,$FA,$37
|
||
|
||
|
||
TFBSetDepth
|
||
;---------------------------------------------------------------------
|
||
; SetDepth sets the TFB depth
|
||
; D1 contains the depth (1,2,4,8}
|
||
; A1 = DCE pointer
|
||
; A2 = parameter block pointer
|
||
; A3 = dCtlStorage pointer
|
||
; Preserves all registers
|
||
;---------------------------------------------------------------------
|
||
|
||
; since we can’t read the mode from the control registers, save copies
|
||
|
||
MOVEM.L D0-D2/A0-A1,-(SP) ;save all regs <EHB12/16>
|
||
|
||
; save the new mode
|
||
|
||
MOVE.W csMode(A2),saveMode(A3) ; save the mode <EHB12/16>
|
||
|
||
; Wait for vertical sync. <C497>
|
||
|
||
BSR WaitVSync ; wait for vertical blanking
|
||
|
||
MOVE.L dctlDevBase(A1),A0 ;A0 <- slot base addr
|
||
ADD.L #TFBBase,A0 ;point to registers
|
||
CMP #8,D1 ;depth too big? <22Sep86>
|
||
BGT.S NoDepth ;=>yes, just exit <EHB 12/16>
|
||
|
||
MOVEQ #0,D0 ;index = 0
|
||
@5 LSR #1,D1 ;shift depth
|
||
BCS.S @10 ;=>got index
|
||
ADDQ #1,D0 ;else next index
|
||
BRA.S @5 ;=>repeat until done
|
||
|
||
@10 MOVE.B #TFBReset,TFBResReg(A0) ;put TFB into reset state
|
||
|
||
|
||
LEA DepthTbl,A1 ;point to depth data
|
||
LSL #4,D0 ;get index into table <16Oct86 GWN>
|
||
ADD D0,A1 ;bump to row for depth
|
||
MOVEQ #$F,D0 ;do 16 bytes
|
||
@20 MOVE.B (A1)+,D1 ;get a byte
|
||
NOT.B D1 ;invert it
|
||
MOVE.B D1,(A0) ;write one byte
|
||
ADDQ #4,A0 ;bump to next register
|
||
DBRA D0,@20 ;=>repeat until done
|
||
|
||
NoDepth MOVEM.L (SP)+,D0-D2/A0-A1 ;restore all regs <EHB 12/16>
|
||
RTS ;return
|
||
|
||
DepthTbl DC.B $20,$47,$00,defmBaseOffset/4,$1E,$E5,$77,$46,$05,$02,$02,$01,$0F,$41,$05,$C8 ;<C439/18Nov86>
|
||
DC.B $40,$47,$00,defmBaseOffset/4,$3C,$E5,$77,$46,$05,$06,$06,$04,$20,$04,$0B,$D8 ;<C439/18Nov86>
|
||
DC.B $80,$47,$00,defmBaseOffset/4,$78,$E5,$77,$46,$05,$0E,$0E,$0A,$42,$8A,$16,$E8 ;<C439/18Nov86>
|
||
DC.B $00,$47,$00,defmBaseOffset/4,$F0,$E5,$77,$46,$05,$1E,$1E,$16,$86,$96,$2D,$F9 ;<C439/18Nov86>
|
||
|
||
|
||
TFBSetPage
|
||
;---------------------------------------------------------------------
|
||
; Entry: D0 = Page # (0 based)
|
||
; A1 = DCE pointer
|
||
; A2 = parameter block pointer
|
||
; A3 = dCtlStorage pointer
|
||
;
|
||
; The base of a page is at dCtlDevBase + 4 + (page * RowBytes * height)
|
||
; The 4 is because we don’t use the first long in the TFB to avoid
|
||
; negative addressing problems.
|
||
;
|
||
; All registers are preserved.
|
||
|
||
MOVEM.L D0-D1/A0-A1,-(SP) ; save all registers <EHB12/16>
|
||
|
||
MOVE D0,savePage(A3) ; save the page <EHB12/16>
|
||
MOVE csMode(A2),D1 ; get the mode <EHB12/17>
|
||
SUB #OneBitMode,D1 ; make it 0 based <EHB12/17>
|
||
LEA ModeTbl,A0 ; point to tables <EHB12/16>
|
||
MULU 4(A0,D1*8),D0 ; calc page * rowBytes <EHB12/16>
|
||
MULU 6(A0,D1*8),D0 ; calc page * rowBytes * height <EHB12/16>
|
||
MOVEQ #defmBaseOffset,D1 ; add offset for TFB <EHB12/16>
|
||
ADD.L D1,D0 ; which doesn’t use first long <EHB12/16>
|
||
MOVE.L D0,D1 ; save offset to page in bytes <EHB12/16>
|
||
MOVE.L dCtlDevBase(A1),A0 ; get base for device <EHB12/16>
|
||
ADD.L A0,D0 ; add the slot’s base address <EHB12/16>
|
||
MOVE.L D0,saveBaseAddr(A3) ; save the base address <EHB12/16>
|
||
|
||
; Now set the hardware by writing the offset in longs to the proper registers.
|
||
|
||
LSR.L #2,D1 ; convert offset to longs <EHB12/16>
|
||
ADD.L #TFBBase,A0 ; point to registers <EHB12/16>
|
||
NOT D1 ; invert the value <EHB12/16>
|
||
MOVE.B D1,wBaseOfstLo(A0) ; set low byte of offset <EHB12/16>
|
||
LSR #8,D1 ; get high byte of offset <EHB12/16>
|
||
MOVE.B D1,wBaseOfstHi(A0) ; set high byte of offset <EHB12/16>
|
||
|
||
MOVEM.L (SP)+,D0-D1/A0-A1 ; restore all registers <EHB12/16>
|
||
RTS ; and return <EHB12/16>
|
||
|
||
|
||
GrayScreen
|
||
;---------------------------------------------------------------------
|
||
; D0 = Page
|
||
; D1 = Mode spID <1.6/DAF>
|
||
; A3 = dCtlStorage Ptr.
|
||
;
|
||
; All registers are preserved.
|
||
|
||
MOVEM.L D0-D4/A0-A1,-(SP) ; save all registers <EHB12/16>
|
||
;+++ <1.6/DAF> MOVE csMode(A2),D1 ; get the mode <EHB12/17>
|
||
|
||
MOVE saveMode(A3),D1 ; get mode ID from driver privates rather <1.7>
|
||
; than csBlock, so you don’t need to pass
|
||
; this to Control_GrayPage
|
||
|
||
SUB #OneBitMode,D1 ; make it 0 based <EHB12/17>
|
||
CMP.W #3,D1 ; if 8-bit req, test for RAM <C804/13Feb87> DAF
|
||
BNE.S @1 ; 1,2,4 bit requests are always OK <C804/13Feb87> DAF
|
||
TST.B VRAM256K(A3) ; is there enough RAM? <C804/13Feb87> DAF
|
||
BNE.S GSDone ; if TRUE, then don’t do anything <C804/13Feb87> DAF
|
||
@1 LEA ModeTbl,A1 ; point to tables <EHB12/16>
|
||
MOVE.L 0(A1,D1*8),D0 ; D0 = the proper pattern <EHB12/16>
|
||
MOVE 4(A1,D1*8),D4 ; D4 = rowbytes for the screen <EHB12/16>
|
||
MOVE 6(A1,D1*8),D3 ; D3 = screen height <EHB12/16>
|
||
SUBQ #1,D3 ; make it 0 based <EHB12/16>
|
||
MOVE.L D0,D1 ; get inverse of pattern <EHB12/16>
|
||
NOT.L D1 ; for alternate lines <EHB12/16>
|
||
|
||
MOVE.L saveBaseAddr(A3),A1 ; point to the current page <EHB12/16>
|
||
NxtRow1 MOVE.L A1,A0 ; get next row <EHB12/16>
|
||
MOVE.W D4,D2 ; get bytes per row <EHB12/16>
|
||
LSR #2,D2 ; get longs per row <EHB12/16>
|
||
SUBQ #1,D2 ; make count 0 based <EHB12/16>
|
||
NxtLong1 MOVE.L D0,(A0)+ ; write gray <EHB12/16>
|
||
DBF D2,NxtLong1 ; for entire width of row <EHB12/16>
|
||
EXG D0,D1 ; get inverse gray for next row <EHB12/16>
|
||
ADD.W D4,A1 ; bump to next row <EHB12/16>
|
||
DBF D3,NxtRow1 ; until no more rows <EHB12/16>
|
||
GSDone
|
||
MOVEM.L (SP)+,D0-D4/A0-A1 ; restore all registers <EHB12/16>
|
||
RTS ; and return <EHB12/16>
|
||
|
||
|
||
; Mode info: Pattern,RowBytes,Height
|
||
|
||
ModeTbl DC.W $AAAA,$AAAA,$0080,$01E0 ; one bit per pixel <EHB12/16>
|
||
DC.W $CCCC,$CCCC,$0100,$01E0 ; two bit per pixel <EHB12/16>
|
||
DC.W $F0F0,$F0F0,$0200,$01E0 ; four bit per pixel <EHB12/16>
|
||
DC.W $FF00,$FF00,$0400,$01E0 ; eight bit per pixel <EHB12/16>
|
||
|
||
|
||
;------------------------------------------------------------- <19Sep86>
|
||
; The Interrupt handler for TFB board
|
||
;-------------------------------------------------------------
|
||
; The interrupt Handler
|
||
; On entry A1 contains the slot base address
|
||
; D0-D3/A0-A3 have been preserved.
|
||
BeginIH MOVE.L A1,A0 ; get screen base
|
||
MOVE.L A1,D0 ; and save for later <C371>
|
||
ADD.L #ClrVInt,A0 ; get offset to register
|
||
CLR.B (A0) ; clear interrupt from card
|
||
|
||
; 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 <C371>
|
||
JSR (A0) ; with slot # in D0 <C371>
|
||
|
||
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 TFBDrvrSize
|
||
TFBDrvrEnd
|
||
TFBDrvrSize Dc.l TFBDrvrEnd-TFBDrvr
|
||
EndP
|
||
Endif
|
||
End
|