mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2025-01-01 11:29:27 +00:00
0ba83392d4
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included. The Tools directory, containing mostly junk, is also excluded.
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
|