sys7.1-doc-wip/Drivers/Video/TFBDriver.a

1631 lines
62 KiB
Plaintext
Raw Normal View History

2020-03-22 08:44:21 +00:00
;
; Hacks to match MacOS (most recent first):
;
; <Sys7.1> 8/3/92 Reverted <SM2>
; 9/2/94 SuperMario ROM source dump (header preserved below)
;
2019-07-27 14:37:48 +00:00
;
; 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 GMs 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 TFBs
; reliance on byte-smearing, which, of course, doesn't work on
; MC60840 machines. Specifically, I changed the Move.ls in the
; WaitVSync routine to Move.bs. 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 dont 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 were 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 DOESNT 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 cant open driver <C715>
BRA.S EndOpen
**********************************************************************
*
* VideoClose releases the devices 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 (doesnt need to be preserved)
* A4 = scratch (must be preserved)
* D0-D3 = scratch (dont 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 dont 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 (its 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 (its 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, were 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 ; =>DONT 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 ; =>DONT 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?
2020-03-22 08:44:21 +00:00
BNE.S BadCtl ; => no, return error <SM2> CSS <Sys7.1>
2019-07-27 14:37:48 +00:00
CMP #8,GDataWidth(A1) ; is data width 8?
2020-03-22 08:44:21 +00:00
BNE.S BadCtl ; => no, return error <SM2> CSS <Sys7.1>
2019-07-27 14:37:48 +00:00
CMP #256,GDataCnt(A1) ; 256 values per channel?
2020-03-22 08:44:21 +00:00
BNE.S BadCtl ; => no, return error <SM2> CSS <Sys7.1>
2019-07-27 14:37:48 +00:00
; 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 its 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 (doesnt need to be preserved)
* D0-D3 = scratch (dont 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 dont 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 doesnt 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 cant 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 dont 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 doesnt 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 slots 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 dont 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 dont 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