mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2026-03-10 23:22:06 +00:00
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.
1830 lines
60 KiB
Plaintext
1830 lines
60 KiB
Plaintext
;
|
|
; File: V8Driver.a
|
|
;
|
|
; Contains: This file contains the video driver for use by the Macintosh
|
|
; OS for the Elsie/V8 hardware.
|
|
;
|
|
; Written by: David Fung/Mike Puckett
|
|
;
|
|
; Copyright: © 1990-1993 by Apple Computer, Inc. All rights reserved.
|
|
;
|
|
; Change History (most recent first):
|
|
;
|
|
; <SM5> 01-08-93 jmp Updated the version number from 0.0 (LC/LC II) to 0.1 (LC930).
|
|
; <SM4> 01-07-93 jmp Fixed a problem where plugging in a VGA-sensed would cause the
|
|
; death-chimes to play (had to do with the fact that we donÕt
|
|
; support gamma tables on VGA displays).
|
|
; <SM3> 11/5/92 SWC Changed VideoEqu.a->Video.a and ShutdownEqu.a->Shutdown.a.
|
|
; <SM2> 11/2/92 kc Don't include SonicEqu.a.
|
|
; <1> 10/6/92 GDW New location for ROMLink tool.
|
|
; <SM4> 09-03-92 jmp (jmp,H6) A couple of labels in the GetEntries code we exiting
|
|
; thru StatGood/StatBad instead of their respective V8
|
|
; counterparts.
|
|
; (jmp,H5) Corrected .s vs. non-.s branches and odd-alignment
|
|
; problems.
|
|
; <SM3> 6/4/92 KW (jmp,H4) Eliminated support for the no-vRAM case.
|
|
; (jmp,H3) Changed the way the base address is gotten and saved.
|
|
; (Use the dCtlDevBase instead of VideoInfo due to the differences
|
|
; between the video base with and without vRAM installed.)
|
|
; (jmp,H1) Roll-in LC II changes. In routine "V8SetEntries" we
|
|
; should have been exiting through V8SEDone instead of SEDone.
|
|
; ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
|
; Pre-SM ROM comments begin here.
|
|
; ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
|
; <2> 3/31/92 JSM Rolled this file into Reality.
|
|
; <1> 12/8/90 HJR First time for Terror.
|
|
; <8> 9/17/90 DAF Integrated code review changes. Relocated fake prime installing
|
|
; routine to Open call, fixed 16-bit gray pattern for alpha,
|
|
; corrected error code ordering in Open, optimized graying loops
|
|
; in two places, improved status flag setting in V8DisableGuts
|
|
; <7> 9/5/90 JJ Rex V8: Fix bug in VDAC equates used in GetEntries.
|
|
; <6> 9/5/90 JJ Fixed screen graying bug in non-vRAM HiRes mode
|
|
; <5> 9/5/90 JJ Corrected bug in screen graying utility (incorrect offset
|
|
; between 256K and 512K tables).
|
|
; <4> 8/30/90 DAF Fix Apple // mode setting in V8SetDepth
|
|
; <3> 8/16/90 JJ Added GetEntries, updated various routines for all vRAM
|
|
; configurations, updated equate names / DAF
|
|
; <2> 8/8/90 JJ Fixed CLUT graying in direct (16-bit) mode
|
|
; <1> 8/7/90 JJ Added Elsie/V8 video driver
|
|
|
|
|
|
STRING C
|
|
|
|
PRINT OFF
|
|
LOAD 'StandardEqu.d'
|
|
|
|
INCLUDE 'DockingEqu.a'
|
|
INCLUDE 'EgretEqu.a'
|
|
INCLUDE 'GestaltEqu.a'
|
|
INCLUDE 'GestaltPrivateEqu.a'
|
|
INCLUDE 'HardwarePrivateEqu.a'
|
|
INCLUDE 'IOPrimitiveEqu.a'
|
|
INCLUDE 'PowerPrivEqu.a'
|
|
INCLUDE 'ROMEqu.a'
|
|
INCLUDE 'Video.a'
|
|
INCLUDE 'SlotMgrEqu.a'
|
|
INCLUDE 'ShutDown.a'
|
|
; INCLUDE 'SonicEqu.a'
|
|
INCLUDE 'UniversalEqu.a'
|
|
|
|
INCLUDE 'DepVideoEqu.a'
|
|
PRINT ON
|
|
|
|
SEG '_sV8Driver'
|
|
|
|
BLANKS ON
|
|
STRING ASIS
|
|
MACHINE MC68020
|
|
|
|
|
|
; This is device storage which is stored in the dCtlStorage field of the DCE.
|
|
|
|
V8VidPrivates RECORD 0
|
|
saveBaseAddr DS.L 1 ; the screen base address
|
|
saveSQElPtr DS.L 1 ; the SQ element pointer (for _SIntRemove).
|
|
saveGammaPtr DS.L 1 ; the pointer to the Gamma correction table
|
|
saveGamDispPtr DS.L 1 ; the pointer to the Gamma block
|
|
saveVDACBase DS.L 1 ; the base addr of the VDAC
|
|
GFlags DS.W 1 ; flags word
|
|
saveMode DS.W 1 ; the current mode setting
|
|
saveID DS.W 1 ; monitor type ID
|
|
saveSlotId DS.W 1 ; spID of video sRsrc (hi-order byte only!)
|
|
V8VidPrivSize EQU *
|
|
ENDR
|
|
|
|
LV8Driver MAIN EXPORT
|
|
|
|
;-------------------------------------------------------------------
|
|
; Video Driver Header
|
|
;-------------------------------------------------------------------
|
|
|
|
|
|
V8Drvr DC.W $4C00 ; ctl,status,needsLock
|
|
DC.W 0,0,0 ; not an ornament
|
|
|
|
; Entry point offset table
|
|
|
|
DC.W V8VidOpen-V8Drvr ; open routine
|
|
DC.W V8Drvr-V8Drvr ; no prime in normal video drivers
|
|
DC.W V8VidCtl-V8Drvr ; control
|
|
DC.W V8VidStatus-V8Drvr ; status
|
|
DC.W V8VidClose-V8Drvr ; close
|
|
|
|
|
|
STRING Pascal
|
|
V8VidTitle DC.B '.Display_Video_Apple_V8'
|
|
ALIGN 2 ; make sure we're aligned
|
|
DC.W CurV8DrvrVersion ; current version
|
|
|
|
STRING ASIS
|
|
|
|
;
|
|
; V8CLUTTbl contains information required to write to the CLUT in the different screen depths.
|
|
; Each depth's information has three values. The first is the number of entries-1 in this depth
|
|
; for range checking. The second is the address of the first active CLUT position for that
|
|
; screen depth. The last number is the ÒskipÓ factor. Unlike the Bt478 vDAC in the ci and Erickson,
|
|
; the Ariel only has adjacent active positions in eight-bit mode. In the lesser depths, the active
|
|
; entries are distributed throughout the CLUT address space. As a result, we use sequential CLUT mode
|
|
; ONLY in eight-bit mode! The skip factor is the address difference between adjacent active positions
|
|
; in each mode.
|
|
;
|
|
; Generally, these rules are true for any particular depth:
|
|
; #entries = (2^^depth)-1
|
|
; startposition = (256 / (2^^depth))-1
|
|
; skipfactor = 256 / (2^^depth)
|
|
|
|
V8CLUTTbl
|
|
DC.B $01,$7F,$00,$80 ; for one-bit mode
|
|
DC.B $03,$3F,$00,$40 ; for two-bit mode
|
|
DC.B $0F,$0F,$00,$10 ; for four-bit mode
|
|
DC.B $FF,$00,$00,$01 ; for eight-bit mode
|
|
|
|
CLUTDatRec RECORD 0 ;
|
|
Range DS.B 1 ; maximum index value in this depth
|
|
Start DS.B 1 ; lowest active CLUT address
|
|
Skip DS.W 1 ; skip value between active addresses
|
|
; (it's a .W to simplify multiplies!)
|
|
ENDR
|
|
|
|
**********************************************************************
|
|
*
|
|
* V8VidOpen allocates private storage for the device in the DCE and locks
|
|
* it down for perpetuity. Also, install the interrupt handler and enable
|
|
* the interrupts.
|
|
*
|
|
* Entry: A0 = param block pointer
|
|
* A1 = DCE pointer
|
|
*
|
|
* Locals: A3 = pointer to private storage
|
|
*
|
|
**********************************************************************
|
|
|
|
WITH VDPageInfo,SlotIntQElement,V8VidPrivates
|
|
|
|
V8VidOpen
|
|
;
|
|
; Allocate private storage (since block is CLEAR, GFlags are zeroed) and get
|
|
; a pointer to it in A3
|
|
;
|
|
|
|
MOVEQ #V8VidPrivSize,D0 ; get size of parameters
|
|
_ResrvMem ,SYS ; make room as low as possible
|
|
MOVEQ #V8VidPrivSize,D0 ; get size of parameters
|
|
_NewHandle ,SYS,CLEAR ; get some memory for private storage
|
|
BNE @OpErrorC ; => return an error in open
|
|
MOVE.L A0,dCtlStorage(A1) ; save returned handle in DCE
|
|
_HLock ; and lock it down forever (this includes a Time Mgr QElem)
|
|
|
|
MOVE.L (A0),A3 ; get a pointer to it
|
|
|
|
;
|
|
; remember the VDAC base address since it's hard to look up.
|
|
;
|
|
|
|
WITH ProductInfo,DecoderInfo,VideoInfo
|
|
MOVE.L UnivInfoPtr,A0 ; get a pointer to universal data
|
|
ADD.L DecoderInfoPtr(A0),A0 ; point to the base address table
|
|
MOVE.L VDACAddr(A0),saveVDACBase(A3) ; save pointer
|
|
ENDWITH
|
|
|
|
;
|
|
; remember the frame buffer base as well. The Open call doesn't set the video mode
|
|
; or page, but SetMode will based on this value
|
|
;
|
|
|
|
MOVE.L dCtlDevBase(A1),saveBaseAddr(A3) ; save the screen base address
|
|
MOVE.B dCtlSlotId(A1),saveSlotId(A3) ; save video sRsrc ID
|
|
|
|
;
|
|
; Get and install the interrupt handler. Call the EnableVGuts utility code to do
|
|
; this. This utility also starts the interrupts going. If there is an error
|
|
; condition, EnableVGuts returns with Z-bit cleared.
|
|
|
|
|
|
MOVEQ #sqHDSize,D0 ; allocate a slot queue element
|
|
_NewPtr ,SYS,CLEAR ; get it from system heap cleared
|
|
BNE @OpErrorB ; if not allocated, return bad
|
|
MOVE.L A0,saveSQElPtr(A3) ; save the SQ element pointer.
|
|
|
|
BSR V8EnableVGuts ; do it
|
|
BNE @OpErrorB ;
|
|
|
|
;
|
|
; read the V8 to find out what kind of monitor we have. To have gotten here, we MUST
|
|
; have a valid video device.
|
|
;
|
|
|
|
MOVE.L V8,A2 ; get the V8 base address
|
|
MOVE.B V8MonP(A2),D0 ; get the monitor type
|
|
LSR.B #3,D0 ; shift Monitor ID into the low bits
|
|
AND.W #7,D0 ; lo 3 bits only
|
|
MOVE.W D0,saveID(A3) ; remember it for later
|
|
|
|
;
|
|
; load the default gamma table from the slot resource list
|
|
;
|
|
|
|
@Gamma
|
|
WITH spBlock
|
|
SUBA #spBlockSize,SP ; make a slot parameter block
|
|
MOVE.L SP,A0 ; get pointer to block in A0
|
|
MOVE.B dCtlSlot(A1),spSlot(A0) ; copy the slot number
|
|
MOVE.B dCtlSlotId(A1),spID(A0) ; copy the spID of the video sRsrc <2.0>
|
|
CLR.B spExtDev(A0) ; <2.0>
|
|
CLR.B spHWDev(A0) ; ????
|
|
|
|
_sRsrcInfo ; get the spsPointer <2.0>
|
|
|
|
MOVE.B #sGammaDir,spID(A0) ; look for the gamma directory
|
|
_sFindStruct ; get that baby
|
|
BNE.S @DoLinear ; if failed, then do linear
|
|
|
|
MOVE.B #$80,spID(A0) ; get the default gamma table, (always 128)
|
|
_sGetBlock ; we can use this since we want it on the sys heap
|
|
BNE.S @DoLinear ; if failed, then do linear
|
|
|
|
;
|
|
; skip over header
|
|
;
|
|
|
|
MOVE.L spResult(A0),A0 ; point to head of the block
|
|
MOVE.L A0,saveGamDispPtr(A3) ; save the ptr to the gamma block
|
|
ADDA #2,A0 ; skip resID
|
|
@Name TST.B (A0)+ ; skip over gamma name
|
|
BNE.S @Name ;
|
|
MOVE.L A0,D0 ; get in d-reg
|
|
ADDQ #1,D0 ; word align pointer
|
|
BCLR.L #0,D0 ; round it off
|
|
|
|
MOVE.L D0,saveGammaPtr(A3) ; put it in private storage
|
|
|
|
;
|
|
; Build a linear default gamma table if necessary.
|
|
;
|
|
|
|
@DoLinear
|
|
Moveq #gFormulaData,D0 ; Get gamma table header size.
|
|
Add #256,D0 ; Add in one-byte per entry.
|
|
_NewPtr ,SYS,CLEAR ; Clear it.
|
|
Bne @OpErrorA ; If failed, quit.
|
|
|
|
Move.l A0,saveGamDispPtr(A3) ; Save head of gamma table for disposal.
|
|
Move.l A0,saveGammaPtr(A3) ; Head and top are same here.
|
|
Move.w #drHwElsie,gType(A0) ; Set up gType.
|
|
Move.w #1,gChanCnt(A0) ; Set up gChanCnt.
|
|
Move.w #256,gDataCnt(A0) ; Set up gDataCnt.
|
|
Move.w #8,gDataWidth(A0) ; Set up gDataWidth.
|
|
Adda #gFormulaData+256,A0 ; Point to end of data table.
|
|
Move.w #255,D0 ; Set up loop counter.
|
|
@Loop Move.b D0,-(A0) ; Write out value.
|
|
Dbra D0,@Loop ; Loop.
|
|
|
|
ADDA #spBlockSize,SP ; release the parameter block
|
|
;
|
|
; all done!
|
|
;
|
|
|
|
@AllDone MOVEQ #0,D0 ; no error
|
|
@EndOpen RTS ; return
|
|
|
|
@OpErrorA ADDA #spBlockSize,SP ; release the spBlock
|
|
@OpErrorB MOVE.L dCtlStorage(A1),A0 ; get the private storage back
|
|
_DisposHandle ; release the driver private storage
|
|
@OpErrorC MOVE.L #OpenErr,D0 ; say can't open driver
|
|
BRA.S @EndOpen
|
|
|
|
ENDWITH
|
|
|
|
|
|
**********************************************************************
|
|
*
|
|
* Video Driver Control Call Handler. There are nine 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 );
|
|
* (4) SetGamma ( Table : Ptr );
|
|
* (5) GrayPage (page);
|
|
* (6) SetGray (csMode = 0 for color, 1 for gray)
|
|
* (7) SetInterrupt ( csMode = 0 for enable, 1 for disable)
|
|
* (8) DirectSetEntries (not implemented)
|
|
* (9) SetDefaultMode
|
|
*
|
|
* 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
|
|
;
|
|
|
|
V8VidCtl MOVE.L A0,-(SP) ; save work registers (A0 is saved because it is used by ExitDrvr)
|
|
|
|
MOVE.W csCode(A0),D0 ; get the opCode
|
|
CMP.W #128,D0 ; is it the restart graying call (id=128?)
|
|
BNE.S @0
|
|
BRA V8Goodbye ; do the graying call
|
|
@0
|
|
MOVE.L csParam(A0),A2 ; A2 <- Ptr to control parameters
|
|
MOVE.L dCtlStorage(A1),A3
|
|
MOVE.L (A3),A3 ; get pointer to private storage
|
|
|
|
CMP.W #9,D0 ; IF csCode NOT IN [0..9] THEN
|
|
BHI.S V8CtlBad ; Error, csCode out of bounds
|
|
MOVE.W V8CtlJumpTbl(PC,D0.W*2),D0 ; Get the relative offset to the routine
|
|
JMP V8CtlJumpTbl(PC,D0.W) ; GOTO the proper routine
|
|
|
|
V8CtlJumpTbl
|
|
DC.W V8VidReset-V8CtlJumpTbl ; $00 => VidReset
|
|
DC.W V8CtlGood-V8CtlJumpTbl ; $01 => CtlGood (no async routines here)
|
|
DC.W V8SetVidMode-V8CtlJumpTbl ; $02 => SetVidMode
|
|
DC.W V8SetEntries-V8CtlJumpTbl ; $03 => SetEntries
|
|
DC.W V8SetGamma-V8CtlJumpTbl ; $04 => SetGamma
|
|
DC.W V8GrayPage-V8CtlJumpTbl ; $05 => GrayPage
|
|
DC.W V8SetGray-V8CtlJumpTbl ; $06 => SetGray
|
|
DC.W V8SetInterrupt-V8CtlJumpTbl ; $07 => SetInterrupt
|
|
DC.W V8DirectSetEntries-V8CtlJumpTbl ; $08 => DirectSetEntries
|
|
DC.W V8SetDefaultMode-V8CtlJumpTbl ; $09 => SetDefaultMode
|
|
|
|
V8CtlBad MOVEQ #controlErr,D0 ; else say we don't do this one
|
|
BRA.S V8CtlDone ; and return
|
|
|
|
V8CtlGood MOVEQ #noErr,D0 ; return no error
|
|
|
|
V8CtlDone MOVE.L (SP)+,A0 ; restore registers.
|
|
BRA V8ExitDrvr
|
|
|
|
|
|
|
|
V8VidReset
|
|
;---------------------------------------------------------------------
|
|
;
|
|
; Reset the card to its default
|
|
;
|
|
;---------------------------------------------------------------------
|
|
|
|
WITH V8VidPrivates
|
|
|
|
MOVE #FirstVidMode,csMode(A2) ; return default mode
|
|
MOVE #FirstVidMode,saveMode(A3) ; remember FirstVidMode as the requested mode
|
|
MOVE #1,D1 ; get default depth in D1
|
|
@2 MOVEQ #0,D0 ; get page in D0
|
|
MOVE D0,csPage(A2) ; return the page
|
|
BSR V8SetDepth ; set the depth from D1
|
|
MOVE.L saveBaseAddr(A3),csBaseAddr(A2) ; return the base address
|
|
BSR V8GrayScreen ; paint the screen gray
|
|
BRA.S V8CtlGood ; => no error
|
|
|
|
ENDWITH
|
|
|
|
|
|
V8SetVidMode
|
|
;---------------------------------------------------------------------
|
|
;
|
|
; Set the card to the specified mode. Only page zero is possible,
|
|
; so we need to check that the request was OK.
|
|
;
|
|
; If the card is already set to the specified mode, then do nothing.
|
|
;
|
|
;---------------------------------------------------------------------
|
|
|
|
WITH V8VidPrivates
|
|
|
|
MOVE.W csMode(A2),D1 ; D1 = mode
|
|
BSR V8ChkMode ; check mode and convert
|
|
BNE.S V8CtlBad ; => not a valid mode
|
|
|
|
TST.W csPage(A2) ; only page zero is valid
|
|
BNE.S V8CtlBad ; => not a valid page
|
|
|
|
; Only set if mode has changed
|
|
|
|
MOVE.W csMode(A2),D2 ; get the mode spID (D1 has the zero-based mode)
|
|
CMP saveMode(A3),D2 ; has the mode changed?
|
|
BEQ.S @ModeOK1 ; if not, then skip graying get out
|
|
|
|
; remember the newly requested mode
|
|
|
|
MOVE.W D2,saveMode(A3) ; remember requested mode
|
|
|
|
; set the entire color table to gray before switching to avoid screen anomalies
|
|
|
|
MOVE.L saveGammaPtr(A3),A0 ; get pointer to gamma data structure
|
|
MOVE GFormulaSize(A0),D3 ; get the size of formula data
|
|
MOVE.W GDataCnt(A0),D2 ; get number of gamma entries
|
|
LSR.W #1,D2 ; divide by two to find midpoint
|
|
LEA GFormulaData(A0),A0 ; point to formula data
|
|
ADD D3,A0 ; first correction table starts here
|
|
MOVE.B (A0,D2),D3 ; get corrected gray from middle of red table
|
|
|
|
; raise to interrupt level 2 the new, good way
|
|
|
|
MOVE.W SR,-(SP) ; preserve the status register
|
|
MOVEQ #7,D2 ; get mask in D0
|
|
AND.B (SP),D2 ; get the interrupt level
|
|
SUBQ.B #2,D2 ;
|
|
BGE.S @OK ; if ³, then don't change
|
|
ORI.W #$0200,SR ; raise above level-2
|
|
ANDI.W #$FAFF,SR ; make it level-2
|
|
@OK
|
|
|
|
BSR V8WaitVSync ; wait for next blanking period
|
|
|
|
; we don't need to test the entire mode here, just blank everything
|
|
|
|
MOVE.L saveVDACBase(A3),A0 ; get the VDAC base addr
|
|
ADDA #V8DACwDataReg,A0 ; point to data register
|
|
CLR.B V8DACwAddReg-V8DACwDataReg(A0) ; start at the beginning of CLUT, 4-bit mode
|
|
|
|
MOVE #(256*3)-1,D2 ; get count <8>
|
|
@Repeat MOVE.B D3,(A0) ; put component (red=green=blue) <8>
|
|
DBRA D2,@Repeat ;
|
|
MOVE (SP)+,SR ; restore the status reg
|
|
|
|
BSR V8SetDepth ; set the depth from D1, page from D0
|
|
|
|
@ModeOK1
|
|
MOVE.L saveBaseAddr(A3),csBaseAddr(A2) ; return the base address
|
|
BRA V8CtlGood ; => return no error
|
|
|
|
ENDWITH
|
|
|
|
|
|
V8SetEntries
|
|
;---------------------------------------------------------------------
|
|
;
|
|
; 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 private data, later to CLUT constants table
|
|
; A4 = Ptr to gamma red table
|
|
; A5 = Ptr to gamma green table
|
|
; A6 = Ptr to gamma blue table
|
|
;
|
|
; D0-D3 = Scratch
|
|
; D4 = Size of stack color table buffer
|
|
; D5 = GFlags word
|
|
; D6 = Index range [0..n]
|
|
; D7 = gamma channel size in bits
|
|
;
|
|
;---------------------------------------------------------------------
|
|
|
|
; Initialize loop.
|
|
|
|
WITH V8VidPrivates
|
|
|
|
BTST #IsDirect,GFlags(A3) ; are we in a direct mode?
|
|
BNE V8CtlBad ; error if so
|
|
|
|
SEGuts
|
|
TST.L csTable(A2) ; Check for a nil pointer
|
|
BEQ V8CtlBad
|
|
|
|
MOVEM.L A1/A4-A6/D4-D7,-(SP) ; save registers for gamma
|
|
|
|
MOVE.W GFlags(A3),D5 ; get GFlags word in D5 (sequence bits are always cleared here)
|
|
|
|
CMP.W #-1,csStart(A2) ; is it sequence mode?
|
|
BEQ.S @5 ; nope, it's index
|
|
BSET #PsuedoIndex,D5 ; turn on the bit that denotes a seq write that was xlated to indexed
|
|
CMP.W #FourthVidMode,saveMode(A3) ; is it 8- or 16-bit mode?
|
|
BLT.S @5 ; if not, need to use indexed mode
|
|
BSET #UseSeq,D5 ; if sequence then set bit
|
|
@5
|
|
MOVE.L saveGammaPtr(A3),A0 ; get pointer to gamma data structure
|
|
MOVE.W GFormulaSize(A0),D0 ; get the size of formula data
|
|
LEA GFormulaData(A0),A4 ; point to formula data
|
|
ADD D0,A4 ; red correction table starts here
|
|
MOVE.L A4,A5 ; get default pointer to green data
|
|
MOVE.L A4,A6 ; get default pointer to blue data
|
|
MOVE GDataWidth(A0),D7 ; get width of each entry in bits
|
|
CMP #1,GChanCnt(A0) ; if only only one table, we're set
|
|
BEQ.S @OneTbl ; => just one table
|
|
|
|
MOVE GDataCnt(A0),D0 ; get # entries in table
|
|
MOVE D7,D1 ; copy it to goof around
|
|
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
|
|
ASL #1,D0 ; mulu times 2
|
|
ADDA D0,A6 ; calc base of blue
|
|
|
|
@OneTbl
|
|
|
|
; save the VDAC base address for later. We're going to torch the privates reg (A3) now
|
|
|
|
MOVE.L saveVDACBase(A3),D6 ; save VDAC base from driver privates
|
|
|
|
; get the maximum number of entries, zero based from a convenient table
|
|
|
|
MOVE.W saveMode(A3),D1 ; get the current video mode
|
|
SUB.W #FirstVidMode,D1 ; convert to index
|
|
|
|
WITH CLUTDatRec
|
|
|
|
LEA (V8CLUTTbl,PC,D1*4),A3 ; point to table of CLUT data
|
|
|
|
;
|
|
; allocate a temporary color table on the stack. We'll pre-process all the entries that will
|
|
; change here so we can hit the hardware as quickly as possible.
|
|
;
|
|
|
|
MOVE.W csCount(A2),D3 ; get the number of entries to change
|
|
CMP.B Range(A3),D3 ; is it in the allowable range?
|
|
BHI V8BadExit ; if outside, then exit w/bad result
|
|
|
|
MOVE.L D3,D4 ; make a copy of the table size (zero-based!)
|
|
ADDQ #1,D4 ; make it a counting number
|
|
BTST #UseSeq,D5 ; are we in index or sequential mode?
|
|
BEQ.S @isIndex ; if equal, we're indexed
|
|
@isSeq MULU #3,D4 ; multiply times 3 for sequential mode
|
|
BRA.S @allocIt ; and continue
|
|
@isIndex ASL #2,D4 ; multiply times 4 (always less than 1024)
|
|
@allocIt SUB.W D4,SP ; allocate the buffer
|
|
|
|
;
|
|
; construct the stack version of the color table. It looks like a color table, but each of the
|
|
; four components is only eight bits (rather than 16).
|
|
;
|
|
|
|
MOVE.L SP,A0 ; copy the stack buffer pointer
|
|
MOVE.L csTable(A2),A1 ; get colorSpec pointer in A1
|
|
|
|
; Death! Totally out of registers in this routine, so I'm using the top half of D4 (the temp buffer
|
|
; size as the sequence counter used in most video modes to translate sequential requests into
|
|
; the indexed write that the hardware needs.
|
|
|
|
SWAP D4 ; flip the buffer size to the top half
|
|
MOVE.W csStart(A2),D4 ; pick up the sequential start position. It might
|
|
; be -1 on a true indexed write, but we won't
|
|
; use it below if it is.
|
|
|
|
; write the index if in indexed mode. If in sequential eight mode, blow it off
|
|
; completely, since it won't be needed.
|
|
|
|
@SetupLoop
|
|
MOVE.W (A1)+,D0 ; get index
|
|
|
|
BTST #UseSeq,D5 ; is it sequence mode?
|
|
BNE.S @SLSeq ; yup, so go there
|
|
|
|
BTST #PsuedoIndex,D5 ; was this an indexed request, or is it a non-8bit sequenc
|
|
BEQ.S @IndexPresent ;
|
|
|
|
; this case is a sequential request in a screen depth that does not allow sequential CLUT writes
|
|
; (any non-8/16 bit mode). In this case, we substitute the sequence counter for D0 on each
|
|
; entry.
|
|
|
|
MOVE.W D4,D0 ; copy sequence counter to D0
|
|
ADDQ.W #1,D4 ; increment sequence counter
|
|
|
|
@IndexPresent
|
|
MULU.W Skip(A3),D0 ; calc the new position at this depth
|
|
ADD.B Start(A3),D0 ; add the first entry offset
|
|
|
|
MOVE.B D0,(A0)+ ; put in stack table
|
|
|
|
@SLSeq
|
|
MOVE.W (A1)+,D0 ; get red
|
|
MOVE.W (A1)+,D1 ; get green
|
|
MOVE.W (A1)+,D2 ; get blue
|
|
|
|
TST D5 ; test hi bit of the flags
|
|
BPL.S @NoGray ; if not set, don't luminence map
|
|
|
|
BTST #IsDirect,D5 ; test for direct mode as well
|
|
BNE.S @NoGray ; don't allow luminence mapping in direct mode
|
|
|
|
|
|
; we're luminence mapping here
|
|
|
|
MULU #$4CCC,D0 ; multiply by red weight (0.30)
|
|
MULU #$970A,D1 ; multiply by green weight (0.59)
|
|
MULU #$1C29,D2 ; multiply by blue weight (0.11)
|
|
ADD.L D1,D0 ; sum red and green
|
|
ADD.L D2,D0 ; blue also
|
|
BFEXTU D0{0:D7},D1 ; get gChanWidth bits for gamma table lookup
|
|
MOVE.W D1,D0 ; copy into red register
|
|
MOVE.W D1,D2 ; copy into blue register
|
|
|
|
BRA.S @WriteSP ; go on and write it in the stack buffer
|
|
|
|
@NoGray
|
|
BFEXTU D0{16:D7},D0 ; get gChanWidth bits of red
|
|
BFEXTU D1{16:D7},D1 ; get gChanWidth bits of green
|
|
BFEXTU D2{16:D7},D2 ; get gChanWidth bits of blue
|
|
|
|
@WriteSP
|
|
MOVE.B (A4,D0),(A0)+ ; write gamma corrected red
|
|
MOVE.B (A5,D1),(A0)+ ; write gamma corrected green
|
|
MOVE.B (A6,D2),(A0)+ ; write gamma corrected blue
|
|
DBRA D3,@SetupLoop ; and loop for each entry
|
|
|
|
ENDWITH
|
|
|
|
SWAP D4 ; put the temp buffer size back in the lo-half
|
|
|
|
;
|
|
; OK, the stack table is set up. Now let's load the hardware.
|
|
;
|
|
|
|
MOVE.W csCount(A2),D3 ; get the count again
|
|
|
|
MOVE.L D6,A3 ; get VDAC base that we pushed above
|
|
|
|
LEA V8DACwDataReg(A3),A3 ; point to vDAC data write register
|
|
|
|
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 V8WaitVSync ; wait for next blanking period (preserves A0)
|
|
|
|
LEA 2(SP),A0 ; point to the stack buffer again
|
|
|
|
BTST #UseSeq,D5 ; is it sequence mode?
|
|
BNE.S @SeqWrite ; yup, sequence mode, so go
|
|
|
|
;
|
|
; here's the loop that actually writes to the hardware when in indexed mode
|
|
;
|
|
|
|
@IndexWrite
|
|
MOVE.B (A0)+,V8DACwAddReg-V8DACwDataReg(A3) ; write the index value to the CLUT address
|
|
MOVE.B (A0)+,(A3) ; write red
|
|
MOVE.B (A0)+,(A3) ; write green
|
|
MOVE.B (A0)+,(A3) ; write blue
|
|
DBRA D3,@IndexWrite ; and loop
|
|
BRA.S V8SEDone ; <H1>
|
|
|
|
; write the translated starting position for sequence mode
|
|
|
|
@SeqWrite
|
|
|
|
MOVE.W csStart(A2),D0 ; get sequence start address (exact since it has to be 8-bit mode)
|
|
MOVE.B D0,V8DACwAddReg-V8DACwDataReg(A3) ; write the sequence start position
|
|
|
|
;
|
|
; here's the loop that actually writes to the hardware when in sequence mode
|
|
;
|
|
|
|
@SeqLoop
|
|
MOVE.B (A0)+,(A3) ; get red
|
|
MOVE.B (A0)+,(A3) ; get green
|
|
MOVE.B (A0)+,(A3) ; write blue
|
|
DBRA D3,@SeqLoop ; and loop
|
|
|
|
;
|
|
; clean up and go home
|
|
;
|
|
|
|
V8SEDone
|
|
MOVE (SP)+,SR ; restore status register
|
|
ADD D4,SP ; release stack buffer
|
|
MOVEM.L (SP)+,A1/A4-A6/D4-D7 ; restore registers
|
|
BRA V8CtlGood ; return O-Tay!
|
|
|
|
V8BadExit
|
|
ADDA #4,SP ; kill pushed vDAC address
|
|
MOVEM.L (SP)+,A1/A4-A6/D4-D7 ; restore registers
|
|
BRA V8CtlBad ; return an error code
|
|
|
|
ENDWITH
|
|
|
|
|
|
V8SetGamma
|
|
;---------------------------------------------------------------------
|
|
;
|
|
; Set the gamma table. This call copies the supplied gTable so the
|
|
; caller does not have to put the source on the system heap. It
|
|
; tests if the gamma table is exactly a match to the currently
|
|
; connected monitor, or always allows it if the monitor number in
|
|
; the FormulaData is -1. If supplied gamma table ptr is NIL, then
|
|
; it loads a linear gamma table into the private table
|
|
;
|
|
; A0 = Ptr to private storage
|
|
; A1 = Ptr to DCE
|
|
; A2 = Ptr to cs parameter record
|
|
;
|
|
;---------------------------------------------------------------------
|
|
|
|
WITH V8VidPrivates
|
|
|
|
; get new gamma table and check that we know how to handle it
|
|
|
|
MOVE.L csGTable(A2),D0 ; test for a NIL pointer
|
|
BEQ V8LinearTab ; if so, then set up a linear gamma table
|
|
MOVE.L D0,A2 ; get pointer to new gamma table
|
|
|
|
TST.W GVersion(A2) ; version = 0?
|
|
BNE V8CtlBad ; => no, return error
|
|
TST.W GType(A2) ; test the hardware ID
|
|
BEQ.S V8ChangeTable ; if 0, then accept a TFB gamma table
|
|
CMP.W #drHwElsie,GType(A2) ; type = Elsie?
|
|
BNE V8CtlBad ; => no, return error
|
|
TST.W gFormulaSize(A2) ; if gType=Aurora, then check for monID in gFormulaData
|
|
BEQ.S V8ChangeTable ; if zero, then generic, so continue
|
|
|
|
MOVE.W gFormulaData(A2),D0 ; get the monitor ID this table was intended for
|
|
CMP.W saveID(A3),D0 ; is this the monitor?
|
|
BEQ.S V8ChangeTable ; yes, so do it
|
|
ADDQ #1,D0 ; was it -1?
|
|
BNE V8CtlBad ; nope, so must be wrong monitor
|
|
|
|
; if new table is different size, reallocate memory
|
|
|
|
V8ChangeTable
|
|
MOVE.L saveGammaPtr(A3),A0 ; get current gamma in A0
|
|
MOVE GFormulaSize(A2),D0 ; get size of formula in new
|
|
CMP GFormulaSize(A0),D0 ; same as current gamma table
|
|
BNE.S @GetNew ; =>no, resize pointer
|
|
MOVE GChanCnt(A2),D0 ; get number of tables in new
|
|
CMP GChanCnt(A0),D0 ; same as current gamma table?
|
|
BEQ.S @SizeOK ; => yes, data size ok
|
|
BGT.S @GetNew ; => new one is bigger, save old one
|
|
@NewSize _DisposPtr ; if new one smaller, dispose old one
|
|
CLR.L saveGammaPtr(A3) ; flag it's been disposed
|
|
|
|
@GetNew MOVE GDataCnt(A2),D0 ; get number of entries
|
|
MULU GChanCnt(A2),D0 ; multiply by number of tables
|
|
ADD GFormulaSize(A2),D0 ; add size of formula data
|
|
ADD #GFormulaData,D0 ; add gamma table header size
|
|
_NewPtr ,Sys ; and allocate a new pointer
|
|
BNE V8CtlBad ; => unable to allocate storage
|
|
|
|
MOVE.L saveGammaPtr(A3),D0 ; get old gamma table
|
|
MOVE.L A0,saveGammaPtr(A3) ; save new gamma table
|
|
TST.L D0 ; was there an old one?
|
|
BEQ.S @SizeOK ; => no, already disposed
|
|
MOVE.L D0,A0 ; else get old table
|
|
_DisposPtr ; and dispose of old gamma table
|
|
|
|
MOVE.L saveGammaPtr(A3),A0 ; get new gamma table back
|
|
|
|
; copy the gamma table header
|
|
|
|
@SizeOK MOVE GChanCnt(A2),D0 ; get number of tables
|
|
MOVE GFormulaSize(A2),D1 ; get size of formula data
|
|
MOVE gDataCnt(A2),D2 ; get number of entries
|
|
MOVE.L (A2)+,(A0)+ ; copy gamma header
|
|
MOVE.L (A2)+,(A0)+ ; which is
|
|
MOVE.L (A2)+,(A0)+ ; 12 bytes long
|
|
|
|
; copy the data
|
|
|
|
MULU D0,D2 ; multiply by number of tables
|
|
ADD D1,D2 ; add in size of formula data
|
|
SUBQ #1,D2 ; get count - 1
|
|
@NxtByte MOVE.B (A2)+,D0 ; get a byte
|
|
MOVE.B D0,(A0)+ ; move a byte
|
|
DBRA D2,@NxtByte ; => repeat for all bytes
|
|
|
|
BTST #IsDirect,GFlags(A3) ; are we in a direct mode?
|
|
BEQ.S @Out ; if not, then we're done
|
|
BSR V8DirectCLUTSet ; is so, then set up direct CLUT ramps
|
|
|
|
@Out
|
|
BRA V8CtlGood ; => return no error
|
|
|
|
;
|
|
; set up a linear gamma table. To prevent memory thrash, build this new one <7>
|
|
; the same size as the existing one (one or three channel).
|
|
;
|
|
|
|
V8LinearTab
|
|
MOVE.L saveGammaPtr(A3),A0 ; get current gamma in A2
|
|
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 #$FF,D0 ; loop count within each channel
|
|
@entryLoop MOVE.B D0,(A0,D0) ; write this value out
|
|
DBRA D0,@entryLoop ; for each entry in channel
|
|
DBRA D2,@ChanLoop ; and each channel
|
|
BRA V8CtlGood ; all done
|
|
|
|
ENDWITH
|
|
|
|
|
|
V8GrayPage
|
|
;---------------------------------------------------------------------
|
|
;
|
|
; Clear the specified page in the current mode to gray
|
|
;
|
|
; A0 = Ptr to private storage
|
|
; A1 = Ptr to DCE
|
|
; A2 = Ptr to cs parameter record
|
|
; A3 = Ptr to driver privates
|
|
;
|
|
;---------------------------------------------------------------------
|
|
|
|
WITH V8VidPrivates
|
|
|
|
MOVE saveMode(A3),D1 ; D1 = mode
|
|
MOVE D1,csMode(A2) ; force current mode, just in case for ChkPage
|
|
BSR V8ChkMode ; convert mode to depth in D1
|
|
BNE V8CtlBad ; => not a valid depth
|
|
|
|
MOVE csPage(A2),D0 ; D0 = page
|
|
BNE V8CtlBad ; => not a valid page
|
|
|
|
BSR V8GrayScreen ; paint the screen gray
|
|
|
|
BTST #IsDirect,GFlags(A3) ; are we in a direct mode?
|
|
BEQ.S @Out ; if not, then we're done
|
|
BSR V8DirectCLUTSet ; is so, then set up direct CLUT ramps
|
|
@Out
|
|
BRA V8CtlGood ; => return no error
|
|
|
|
ENDWITH
|
|
|
|
|
|
V8SetGray
|
|
;---------------------------------------------------------------------
|
|
;
|
|
; Set luminance mapping on (csMode = 1) or off (csMode = 0)
|
|
;
|
|
; When luminance mapping is on, RGB values passed to setEntries are mapped
|
|
; to grayscale equivalents before they are written to the CLUT.
|
|
;
|
|
; A1 = Ptr to DCE
|
|
; A2 = Ptr to cs parameter record
|
|
;
|
|
;---------------------------------------------------------------------
|
|
|
|
WITH V8VidPrivates
|
|
|
|
MOVEQ #0,D1 ; set up for BFEXTU to point to GrayFlag
|
|
BSR.S V8SetIntCom ; call common code
|
|
BRA V8CtlGood ; all done
|
|
|
|
;
|
|
; this shared routine setup up a flag in GFlags. It takes a pointer to
|
|
; private storage in A3, and the bit field start location in D1
|
|
;
|
|
|
|
V8SetIntCom
|
|
MOVE.B csMode(A2),D0 ; get boolean
|
|
BFINS D0,GFlags(A3){D1:1} ; set flag bit
|
|
RTS ; and return
|
|
|
|
ENDWITH
|
|
|
|
|
|
V8SetInterrupt
|
|
;---------------------------------------------------------------------
|
|
;
|
|
; Enable (csMode = 0) or disable (csMode = 1) VBL interrupts
|
|
;
|
|
; As a future performance enhancement, interrupts on the card can be
|
|
; disabled or enabled from software. For instance, if the cursor is
|
|
; not on a screen, and there is nothing in the Slot Interrupt Queue
|
|
; for that device, interrupts may be disabled reducing interrupt
|
|
; overhead for the system.
|
|
;
|
|
; The slot interrupt queue element is always allocated by the Open call.
|
|
; This routine just inserts and removes it from the slot interrupt task queue.
|
|
;
|
|
; A1 = Ptr to DCE
|
|
; A2 = Ptr to cs parameter record
|
|
; A3 = Ptr to private storage
|
|
;
|
|
;---------------------------------------------------------------------
|
|
|
|
WITH VDPageInfo,SlotIntQElement,V8VidPrivates
|
|
|
|
MOVEQ #1,D1 ; set up for BFEXTU to point to IntDisFlag
|
|
BSR.S V8SetIntCom ; call common code
|
|
BNE.S V8DisableThem ; if zero, then enable
|
|
|
|
;
|
|
; this code enables interrupts and installs the interrupt handler
|
|
;
|
|
|
|
BSR.S V8EnableVGuts ; call common code
|
|
BNE V8CtlBad ; error, flag problem
|
|
BRA V8CtlGood ; and go home
|
|
|
|
;
|
|
; this code disables VBL interrupts, then removes the interrupt handler
|
|
;
|
|
|
|
V8DisableThem
|
|
BSR.S V8DisableVGuts ; jump to the disabling utility
|
|
BRA V8CtlGood ; all done
|
|
|
|
;
|
|
; the following two routines are common code shared between the Open/Close calls
|
|
; and the SetInterrupt control call
|
|
;
|
|
|
|
V8DisableVGuts
|
|
MOVE.W SR,-(SP) ; preserve the status register
|
|
MOVEQ #7,D0 ; get mask in D0
|
|
AND.B (SP),D0 ; get the interrupt level
|
|
SUBQ.B #2,D0 ;
|
|
BGE.S @OK ; if ³, then don't change
|
|
ORI.W #$0200,SR ; raise above level-2
|
|
ANDI.W #$FAFF,SR ; make it level-2
|
|
@OK
|
|
|
|
BSR V8WaitVSync ; to be safe, wait for the next VBL
|
|
MOVE.L V8,A0 ; point to the VISA base
|
|
MOVE.B #$40,V8SEnb(A0) ; set slot 0 interrupt disabled (slot 0 bit+set/clear to 0) <1.3>
|
|
MOVE (SP)+,SR ; re-enable cursor interrupts
|
|
|
|
CLR D0 ; setup slot # for _SIntRemove (slot zero!)
|
|
MOVE.L saveSQElPtr(A3),A0 ; get the SQ element pointer
|
|
_SIntRemove ; remove the interrupt handler
|
|
RTS
|
|
|
|
V8EnableVGuts ;
|
|
MOVE.L saveSQElPtr(A3),A0 ; get the queue element
|
|
LEA V8BeginIH,A2 ; save Pointer to interrupt handler
|
|
MOVE.W #SIQType,SQType(A0) ; setup queue ID
|
|
MOVE.L A2,SQAddr(A0) ; setup int routine address
|
|
MOVE.L dCtlStorage(A1),A2 ; base handle to privates
|
|
MOVE.L (A2),A2 ; pointer to privates (this must stay locked!!)
|
|
MOVE.L A2,SQParm(A0) ; pass this as the parameter
|
|
CLR.W D0 ; setup slot zero
|
|
_SIntInstall ; and do install
|
|
BNE.S @IntBad
|
|
|
|
MOVE.L A0,-(SP) ; save this for a second
|
|
MOVE.L V8,A0 ; point to the RBV base
|
|
MOVE.B #$C0,V8SEnb(A0) ; set slot 0 interrupt enabled (slot 0 bit+set/clear to 1) <1.3>
|
|
MOVE.L (SP)+,A0
|
|
|
|
MOVE D0,D0 ; clear z-bit for good result
|
|
@IntBad RTS ; return home (if bad, z-bit is set above, so just leave) <8>
|
|
|
|
ENDWITH
|
|
|
|
|
|
|
|
V8DirectSetEntries
|
|
;---------------------------------------------------------------------
|
|
;
|
|
; Change the CLUT in a direct mode.
|
|
;
|
|
; A1 = Ptr to DCE
|
|
; A2 = Ptr to cs parameter record
|
|
; A3 = Ptr to private storage
|
|
;
|
|
; This routine allows knowledgeable programs modify the contents
|
|
; of the CLUT in direct modes (usually for limited color previewing).
|
|
; It takes the same parameter block as SetEntries, but SetEntries
|
|
; intentionally does not operate when the card is in a direct pixMode.
|
|
; This routine takes the same data and operates ONLY when in direct
|
|
; modes. It calls the same SetEntries guts as the regular routine.
|
|
;
|
|
;---------------------------------------------------------------------
|
|
|
|
BTST #IsDirect,GFlags(A3) ; are we in a direct mode?
|
|
BEQ V8CtlBad ; error if not
|
|
CMP.W #31,csCount(A2) ; only 32 changeable positions in direct mode
|
|
BGT V8CtlBad ; error if not
|
|
BRA SEGuts ; jump to SetEntries internals if it's OK
|
|
|
|
|
|
|
|
V8SetDefaultMode
|
|
;---------------------------------------------------------------------
|
|
;
|
|
; Write the card default mode into slot pRAM.
|
|
;
|
|
; A1 = Ptr to DCE
|
|
; A2 = Ptr to cs parameter record
|
|
; A3 = Ptr to private storage
|
|
;
|
|
; This routine is called by Monitors when somebody selects an alternate
|
|
; video mode family in the Options dialog.
|
|
;
|
|
;---------------------------------------------------------------------
|
|
|
|
WITH spBlock,V8VidPrivates
|
|
|
|
;
|
|
; set up a slot parameter block on the stack
|
|
;
|
|
|
|
|
|
SUBA #spBlockSize,SP ; make an slot parameter block on stack
|
|
MOVE.L SP,A0 ; get pointer to parm block now
|
|
MOVE.B dCtlSlot(A1),spSlot(A0) ; put slot in pBlock
|
|
CLR.B spExtDev(A0) ; external device = 0
|
|
|
|
|
|
;
|
|
; read the slot pRAM to determine what the currently saved mode is. The first
|
|
; word is the board ID, followed by the default screen depth. Aurora keeps the video sRsrc
|
|
; spID in VendorUse2. This guy DOESN'T check to make sure that the mode being set if
|
|
; valid for the display, but that's OK since Monitors can't see the other modes anyway
|
|
;
|
|
|
|
SUBA #SizesPRAMRec,SP ; allocate block for pRAM record
|
|
MOVE.L SP,spResult(A0) ; point to it
|
|
_sReadPRAMRec ; read it
|
|
|
|
;
|
|
; The parameter list id (identifying the screen depth) in 2(SP) will still be valid.
|
|
;
|
|
; It is very important that Monitors (or someone) invalidate and setup the screen resource
|
|
; if this call is exercised. Monitors needs to verify (and potentially re-write to pRAM)
|
|
; the proper screen depth in the new world.
|
|
;
|
|
|
|
MOVE.B csMode(A2),3(SP) ; write the mode into pRAM buffer
|
|
|
|
MOVE.L SP,spsPointer(A0) ; set up parameter block
|
|
_SPutPRAMRec ; write the new record out
|
|
ADDA #SizesPRAMRec+spBlockSize,SP ; deallocate buffer
|
|
BRA V8CtlGood
|
|
|
|
ENDWITH
|
|
|
|
|
|
V8Goodbye
|
|
;---------------------------------------------------------------------
|
|
;
|
|
; Special routine to entire CLUT to 50% gray.
|
|
;
|
|
; Since the VISA can't suppress video sync, we gray out the CLUT on
|
|
; restart to hide any mode change artifacts. We could have buried this
|
|
; code in the Shutdown.a, but it's better to collect all the device
|
|
; specific code here.
|
|
;
|
|
; No parameters
|
|
;
|
|
;---------------------------------------------------------------------
|
|
|
|
; raise to interrupt level 2 the new, good way
|
|
|
|
MOVE.W SR,-(SP) ; preserve the status register
|
|
MOVEQ #7,D2 ; get mask in D0
|
|
AND.B (SP),D2 ; get the interrupt level
|
|
SUBQ.B #2,D2 ;
|
|
BGE.S @OK ; if ³, then don't change
|
|
ORI.W #$0200,SR ; raise above level-2
|
|
ANDI.W #$FAFF,SR ; make it level-2
|
|
@OK
|
|
|
|
; blank everything
|
|
|
|
WITH ProductInfo,DecoderInfo,VideoInfo
|
|
MOVE.L UnivInfoPtr,A0 ; get a pointer to universal data
|
|
ADD.L DecoderInfoPtr(A0),A0 ; point to the base address table
|
|
MOVE.L VDACAddr(A0),A0 ; get chip base address
|
|
ADDA #V8DACwDataReg,A0 ; point to data register
|
|
CLR.B V8DACwAddReg-V8DACwDataReg(A0) ; start at the beginning of CLUT, 4-bit mode
|
|
ENDWITH
|
|
|
|
MOVE.B #$7F,D3 ; get a 50% value
|
|
MOVE #($256*3)-1,D2 ; get count <8>
|
|
@Repeat MOVE.B D3,(A0) ; put component (red=green=blue) <8>
|
|
DBRA D2,@Repeat ;
|
|
MOVE (SP)+,SR ; restore the status reg
|
|
BRA V8CtlGood
|
|
|
|
|
|
**********************************************************************
|
|
*
|
|
* VideoClose releases the device's private storage and removes the
|
|
* interrupt handler.
|
|
*
|
|
*
|
|
* Entry: A0 = param block pointer
|
|
* A1 = DCE pointer
|
|
*
|
|
* Other: A2 = temporary DCE pointer copy
|
|
*
|
|
**********************************************************************
|
|
|
|
V8VidClose
|
|
|
|
WITH V8VidPrivates
|
|
|
|
MOVE.L dCtlStorage(A1),A3
|
|
MOVE.L (A3),A3 ; get pointer to private storage
|
|
|
|
BSR V8DisableVGuts ; call utility to deactivate interrupts
|
|
|
|
MOVE.L saveSQElPtr(A3),A0 ; get the slot interrupt queue element ptr
|
|
_DisposPtr
|
|
|
|
MOVE.L saveGamDispPtr(A3),A0 ; get pointer to gamma table block
|
|
_DisposPtr ; and dispose it
|
|
|
|
MOVE.L dCtlStorage(A1),A0 ; Dispose of the private storage
|
|
_DisposHandle ;
|
|
|
|
MOVEQ #0,D0 ; no error
|
|
RTS ; and return
|
|
|
|
ENDWITH
|
|
|
|
|
|
**********************************************************************
|
|
*
|
|
* Video Driver Status Call Handler. Right now there are nine calls:
|
|
*
|
|
* (0) Error
|
|
* (1) Error
|
|
* (2) GetMode
|
|
* (3) GetEntries
|
|
* (4) GetPage
|
|
* (5) GetPageBase
|
|
* (6) GetGray
|
|
* (7) GetInterrupt
|
|
* (8) GetGamma
|
|
* (9) GetDefaultMode
|
|
*
|
|
* Entry: A0 = param block
|
|
* A1 = DCE pointer
|
|
* Uses: A2 = cs parameters
|
|
* A3 = pointer to private storage
|
|
* D0-D3 = scratch (don't need to be preserved)
|
|
*
|
|
* Exit: D0 = error code
|
|
*
|
|
**********************************************************************
|
|
|
|
V8VidStatus
|
|
|
|
MOVE.L A0,-(SP) ; save a register
|
|
MOVE.W csCode(A0),D0 ; get the opCode
|
|
MOVE.L csParam(A0),A2 ; A2 <- Ptr to control parameters
|
|
MOVE.L dCtlStorage(A1),A3
|
|
MOVE.L (A3),A3 ; get pointer to private storage
|
|
|
|
|
|
CMP.W #9,D0 ;IF csCode NOT IN [0..9] THEN
|
|
BHI.S V8StatBad ; Error, csCode out of bounds.
|
|
LSL.W #1,D0 ;Adjust csCode to be an index into the table.
|
|
MOVE.W V8StatJumpTbl(PC,D0.W),D0 ;Get the relative offset to the routine.
|
|
JMP V8StatJumpTbl(PC,D0.W) ;GOTO the proper routine.
|
|
|
|
V8StatJumpTbl
|
|
DC.W V8StatBad-V8StatJumpTbl ;$00 => Error
|
|
DC.W V8StatBad-V8StatJumpTbl ;$01 => Error
|
|
DC.W V8GetMode-V8StatJumpTbl ;$02 => GetMode
|
|
DC.W V8GetEntries-V8StatJumpTbl ;$03 => GetEntries
|
|
DC.W V8GetPage-V8StatJumpTbl ;$04 => GetPage
|
|
DC.W V8GetPageBase-V8StatJumpTbl ;$05 => GetPageBase
|
|
DC.W V8GetGray-V8StatJumpTbl ;$06 => GetGray
|
|
DC.W V8GetInterrupt-V8StatJumpTbl ;$07 => GetInterrupt
|
|
DC.W V8GetGamma-V8StatJumpTbl ;$08 => GetGamma
|
|
DC.W V8GetDefaultMode-V8StatJumpTbl ;$09 => GetDefaultMode
|
|
|
|
|
|
V8StatBad MOVEQ #statusErr,D0 ; else say we don't do this one
|
|
BRA.S V8StatDone ; and return
|
|
|
|
V8StatGood MOVEQ #noErr,D0 ; return no error
|
|
|
|
V8StatDone MOVE.L (SP)+,A0 ; restore registers.
|
|
BRA V8ExitDrvr
|
|
|
|
|
|
V8GetMode
|
|
;---------------------------------------------------------------------
|
|
;
|
|
; Return the current mode
|
|
;
|
|
; Inputs : A2 = pointer to csParams
|
|
; A3 = pointer to private storage
|
|
;
|
|
;---------------------------------------------------------------------
|
|
|
|
WITH V8VidPrivates
|
|
|
|
MOVE.W saveMode(A3),csMode(A2) ; return the mode
|
|
MOVE.W #0,csPage(A2) ; return the page number (always 0)
|
|
MOVE.L saveBaseAddr(A3),csBaseAddr(A2) ; and the base address
|
|
|
|
BRA.S V8StatGood ; => return no error
|
|
|
|
ENDWITH
|
|
|
|
|
|
V8GetEntries
|
|
;---------------------------------------------------------------------
|
|
;
|
|
; Read the current contents of the CLUT. These values were gamma corrected
|
|
; when they were set (by SetEntries), so they may not match the source
|
|
; cSpec array.
|
|
;
|
|
; Inputs : A2 = pointer to csParams
|
|
;
|
|
;---------------------------------------------------------------------
|
|
|
|
MOVE.L csTable(A2),D0 ; Check for a nil pointer
|
|
BEQ V8StatBad
|
|
|
|
MOVEM.L A1/A3-A4/D2-D5,-(SP) ; save work registers
|
|
MOVE.L D0,A4 ; A4 <- pointer to table
|
|
|
|
; get the index range in D3
|
|
|
|
WITH CLUTDatRec
|
|
LEA V8CLUTTbl,A0 ; point to CLUT parameters
|
|
MOVE.W saveMode(A3),D0 ; get the screen depth ID
|
|
SUB #FIrstVidMode,D0 ; make it an index
|
|
|
|
MOVE.B Range(A0,D0*4),D3 ; get the maximum CLUT index
|
|
MOVE.B Start(A0,D0*4),D4 ; get the starting position
|
|
MOVE.W Skip(A0,D0*4),D5 ; get the inter-entry skip value
|
|
ENDWITH
|
|
|
|
MOVE.W csCount(A2),D0 ; get the count
|
|
MOVE.W D0,D2 ; make a copy of the count
|
|
|
|
TST.W csStart(A2) ; is it index or sequence mode?
|
|
BMI.S V8GECom ; if index, then continue
|
|
|
|
MOVE.W D0,D1 ; copy count into another loop counter
|
|
ADD.W csStart(A2),D2 ; get last index
|
|
@1
|
|
MOVE.W D2,value(A4,D1*8) ; write the index into the table
|
|
SUBQ #1,D2 ; decrease index
|
|
DBRA D1,@1 ; for all indices
|
|
|
|
V8GECom
|
|
|
|
MOVE.L saveVDACBase(A3),A1 ; get base address of CLUT
|
|
ADDQ #v8DACwDataReg,A1 ; read and write data are the same register
|
|
|
|
MOVE.W SR,-(SP) ; preserve the status register
|
|
MOVEQ #7,D1 ; get mask in D0
|
|
AND.B (SP),D1 ; get the interrupt level
|
|
SUBQ.B #2,D1 ;
|
|
BGE.S @OK ; if ³, then don't change
|
|
ORI.W #$0200,SR ; raise above level-2
|
|
ANDI.W #$FAFF,SR ; make it level-2
|
|
@OK
|
|
|
|
@Repeat
|
|
MOVE.W (A4)+,D1 ; get the value field for from the next colorspec in D1
|
|
CMP.B D3,D1 ; Is this request in range?
|
|
BHI.S @Until ; if hi, then no, the request is invalid
|
|
|
|
MULU D5,D1 ; multiply index by skip value
|
|
ADD.B D4,D1 ; add starting offset
|
|
MOVE.B D1,V8DACrAddReg-V8DACwDataReg(A1) ; set the CLUT to read from this addr <7><daf,jj>
|
|
|
|
MOVEQ #3-1,D6 ; loop counter for # of channels
|
|
@CLUTLoop MOVE.B (A1),D1 ; get value
|
|
MOVE.B D1,(A4)+ ; byte->word in the dest cSpecArray
|
|
MOVE.B D1,(A4)+ ;
|
|
DBRA D6,@CLUTLoop ; for each channel
|
|
|
|
@Until DBRA D0,@Repeat ; and loop until done
|
|
|
|
MOVE (SP)+,SR ; restore the status register
|
|
|
|
MOVEM.L (SP)+,A1/A3-A4/D2-D5 ; restore work register
|
|
BRA V8StatGood ; => return no error
|
|
|
|
|
|
|
|
V8GetPage
|
|
;---------------------------------------------------------------------
|
|
;
|
|
; Return the number of pages in the specified mode. It's pretty simple;
|
|
; every mode has only one page. We do check if it's valid, however.
|
|
;
|
|
;---------------------------------------------------------------------
|
|
|
|
WITH V8VidPrivates
|
|
|
|
MOVE csMode(A2),D1 ; get the mode
|
|
MOVE D1,D2 ; keep a copy
|
|
BSR.S V8ChkMode ; is this mode OK?
|
|
BGT V8StatBad ; => not a valid mode
|
|
|
|
MOVE.W #1,csPage(A2) ; return page count
|
|
BRA V8StatGood ; => return no error
|
|
|
|
ENDWITH
|
|
|
|
|
|
V8GetPageBase
|
|
;---------------------------------------------------------------------
|
|
;
|
|
; Return the base address for the specified page in the current mode
|
|
;
|
|
;---------------------------------------------------------------------
|
|
|
|
WITH V8VidPrivates
|
|
|
|
TST.W csPage(A2) ; are we returning page zero info?
|
|
BNE V8StatBad ; only page 0 is valid
|
|
|
|
MOVE.L saveBaseAddr(A3),csBaseAddr(A2) ; return screen base address
|
|
BRA V8StatGood ; => return no error
|
|
|
|
ENDWITH
|
|
|
|
|
|
V8GetGray
|
|
;---------------------------------------------------------------------
|
|
;
|
|
; Return a boolean, set true if luminance mapping is on
|
|
;
|
|
;---------------------------------------------------------------------
|
|
|
|
WITH V8VidPrivates
|
|
|
|
MOVEQ #0,D1 ; set up for BFEXTU
|
|
V8GetFlagCom
|
|
BFEXTU GFlags(A3){D1:1},D0 ; get the state of flag
|
|
MOVE.B D0,csMode(A2) ; return value
|
|
BRA V8StatGood ; => and return
|
|
|
|
ENDWITH
|
|
|
|
|
|
V8GetInterrupt
|
|
;---------------------------------------------------------------------
|
|
;
|
|
; Return a boolean in csMode, set true if VBL interrupts are disabled
|
|
;
|
|
;---------------------------------------------------------------------
|
|
|
|
WITH V8VidPrivates
|
|
|
|
MOVEQ #1,D1 ; set up BFEXTU to point at IntDisFlag
|
|
BRA.S V8GetFlagCom ; and use common code
|
|
|
|
ENDWITH
|
|
|
|
|
|
V8GetGamma
|
|
;---------------------------------------------------------------------
|
|
;
|
|
; Return the pointer to the current gamma table
|
|
;
|
|
;---------------------------------------------------------------------
|
|
|
|
WITH V8VidPrivates
|
|
|
|
MOVE.L saveGammaPtr(A3),csGTable(A2) ; return the pointer to the structure
|
|
BRA V8StatGood ; and return a good result
|
|
|
|
ENDWITH
|
|
|
|
|
|
V8GetDefaultMode
|
|
;---------------------------------------------------------------------
|
|
;
|
|
; Read the card default mode from slot pRAM.
|
|
;
|
|
; A1 = Ptr to DCE
|
|
; A2 = Ptr to cs parameter record
|
|
; A3 = Ptr to private storage
|
|
;
|
|
;---------------------------------------------------------------------
|
|
|
|
WITH spBlock,V8VidPrivates
|
|
|
|
;
|
|
; set up a slot parameter block on the stack
|
|
;
|
|
|
|
SUBA #spBlockSize,SP ; make an slot parameter block on stack
|
|
MOVE.L SP,A0 ; get pointer to parm block now
|
|
MOVE.B dCtlSlot(A1),spSlot(A0) ; put slot in pBlock
|
|
CLR.B spExtDev(A0) ; external device = 0
|
|
|
|
;
|
|
; read the slot pRAM to determine what the currently saved mode is. The first
|
|
; byte is the board ID, followed by the default mode. Aurora keeps the last
|
|
; selected video sRsrc spID in VendorUse2.
|
|
;
|
|
|
|
SUBA #SizesPRAMRec,SP ; allocate block for pRAM record
|
|
MOVE.L SP,spResult(A0) ; point to it
|
|
_sReadPRAMRec ; read it
|
|
|
|
MOVE.B 3(SP),csMode(A2) ; return the result
|
|
ADDA #SizesPRAMRec+spBlockSize,SP ; release buffer
|
|
BRA V8StatGood ;
|
|
|
|
ENDWITH
|
|
|
|
|
|
;---------------------------------------------------------------------
|
|
;
|
|
; Exit from control or Status.
|
|
;
|
|
;---------------------------------------------------------------------
|
|
|
|
V8ExitDrvr BTST #NoQueueBit,ioTrap(A0) ; no queue bit set?
|
|
BEQ.S V8GoIODone ; => no, not immediate
|
|
RTS ; otherwise, it was an immediate call
|
|
|
|
V8GoIODone MOVE.L JIODone,A0 ; get the IODone address
|
|
JMP (A0) ; invoke it
|
|
|
|
|
|
|
|
|
|
;=====================================================================
|
|
;
|
|
; Utilities
|
|
;
|
|
;=====================================================================
|
|
|
|
;---------------------------------------------------------------------
|
|
;
|
|
; ChkMode
|
|
;
|
|
; Verifies the requested mode is legal. Converts spID in D1 into
|
|
; zero-based mode number since lots of people want it that way.
|
|
;
|
|
; <-> D1: Mode
|
|
; -> A3: Pointer to driver privates
|
|
;
|
|
; All registers preserved
|
|
;
|
|
; Returns EQ if mode is valid.
|
|
;
|
|
|
|
V8ChkMode
|
|
|
|
WITH V8VidPrivates
|
|
|
|
MOVEM.L D0/D2-D3,-(SP) ; save regs
|
|
|
|
SUB.W #FirstVidMode,D1 ; make modeID zero based
|
|
MOVE.B saveSlotID(A3),D0 ; get the slot manager mode ID
|
|
|
|
BCLR #4,D0 ; if this bit is on, either A// mode or no vRAM
|
|
BEQ.S @testDepth ; if not, then do simple test
|
|
|
|
; if we are in A// emulation mode, then warp D0 to make the monitor look like a High-Res rather than a Rubik.
|
|
; We do this because the V8 has one less mode available when in A// mode (8-bit only with 512K vRAM, 4-bit
|
|
; with 256K vRAM). Note that the A// mode bit was flipped off in a test above!
|
|
|
|
@adjA2Em
|
|
BSET #2,D0 ; transmogrify A// Rubik into High-Res
|
|
|
|
; test for the greatest available depth. We'll set this up in D2 and compare to D1
|
|
|
|
@testDepth
|
|
MOVE #ThirdVidMode-FirstVidMode,D2 ; everybody at this point can do 4-bit mode
|
|
|
|
;+++ BTST #2,D0 ; Rubiks have one more possible mode over Hi-Res & VGA
|
|
MOVE.B D0,D3 ; copy the spID
|
|
AND.B #5,D3 ; Rubik = 010, HR=110, VGA=011, so we test for
|
|
; Rubik by making sure bits 0 and 2 are clear
|
|
|
|
BNE.S @vRAMTest ; if not, then continue
|
|
|
|
ADDQ #1,D2 ; reflect the additional mode
|
|
|
|
@vRAMTest
|
|
BTST #3,D0 ; 512K machines get one additional mode in all display flavors
|
|
BNE.S @ShowDown ;
|
|
|
|
ADDQ #1,D2 ; reflect the additional mode
|
|
|
|
@ShowDown CMP.B D2,D1 ; see if we're OK
|
|
BGT.S @ModeBad ; if D2>D1, it's an illegal mode
|
|
|
|
@ModeOK CMP.W D1,D1 ; get EQ
|
|
|
|
@ModeBad MOVEM.L (SP)+,D0/D2-D3 ; restore trashed regs
|
|
@ModeOut RTS ; EQ if valid depth
|
|
|
|
ENDWITH
|
|
|
|
|
|
|
|
;---------------------------------------------------------------------
|
|
;
|
|
; Wait for vertical blanking. Interrupts are raised to level-2 around
|
|
; this routine.
|
|
;
|
|
; A1 = DCE POINTER
|
|
;---------------------------------------------------------------------
|
|
|
|
V8WaitVSync
|
|
|
|
MOVE.L A0,-(SP) ; save work registers <8>
|
|
MOVE.L D0,-(SP) ; (two MOVEs are faster than a MOVEM) <8>
|
|
|
|
MOVE.L V8,A0 ; point to VISA
|
|
MOVE.B #$40,V8SInt(A0) ; clear the interrupt, just in case,
|
|
; since the intHndlr can't get
|
|
; called here
|
|
|
|
ADDA #V8SInt,A0 ; point to interrupt register
|
|
|
|
@0 MOVE.B (A0),D0 ; Read the Vert-Sync state
|
|
BTST #6,D0 ;
|
|
BNE.S @0 ; Repeat until it goes low
|
|
;
|
|
MOVE.L (SP)+,D0 ; restore work registers <8>
|
|
MOVE.L (SP)+,A0 ; (two MOVES are faster than a MOVEM) <8>
|
|
RTS
|
|
|
|
|
|
V8SetDepth
|
|
;---------------------------------------------------------------------
|
|
;
|
|
; SetDepth sets the V8 frame buffer depth, and returns the
|
|
; frame buffer base in driver privates
|
|
;
|
|
; D0 contains the page number
|
|
; D1 contains the spID of the depth - $80 (the zero based mode ID)
|
|
; A2 = parameter block pointer
|
|
; A3 = dCtlStorage pointer
|
|
;
|
|
; Preserves all registers
|
|
;
|
|
;---------------------------------------------------------------------
|
|
|
|
|
|
WITH V8VidPrivates
|
|
|
|
MOVEM.L D2/D3/A0/A1,-(SP) ; save regs we are using <1.8>
|
|
|
|
MOVE.B D1,D3 ; make a copy of the depth value
|
|
|
|
; Test for Apple // mode. If it is this mode, then we need to set the V8 to the next greater
|
|
; depth.
|
|
|
|
MOVE.B saveSlotId(A3),D2 ; get spID in a register
|
|
AND.B #$F7,D2 ; don't look at the vRAM size bit
|
|
CMP.B #sRsrc_Vid_V8_A2Ema,D2 ; compare to 512K Apple // mode
|
|
BNE.S @0
|
|
ADDQ #1,D3 ; bump the depth up by one
|
|
@0
|
|
MOVE.L V8,A0 ; point to Elsie base
|
|
MOVE.B V8MonP(A0),D2 ; get the V8 state
|
|
AND.B #ClrDepthBitsMask,D2 ; clear the lo-3 bits (depth control)
|
|
OR.B D3,D2 ; turn on the depth bits
|
|
MOVE.B D2,V8MonP(A0) ; set the mode
|
|
|
|
; set up the Ariel
|
|
|
|
MOVE.L saveVDACBase(A3),A0 ; point to the DAC
|
|
MOVE.B V8DACrCntlReg(A0),D2 ; get the Ariel control register value
|
|
AND.B #ClrDepthBitsMask,D2 ; clear the depth bits
|
|
OR.B D1,D2 ; set the new depth
|
|
MOVE.B D2,V8DACwCntlReg(A0) ; set the new control register value
|
|
@CalcBase
|
|
MOVE.W csMode(A2),saveMode(A3) ; save mode number
|
|
CMP.W #FifthVidMode,saveMode(A3) ; was it 16-bit mode?
|
|
BNE.S @BitOff ; no, so turn flag off
|
|
|
|
BSET #IsDirect,GFlags(A3) ; turn on bit
|
|
BRA.S @Out ;
|
|
@BitOff
|
|
BCLR #IsDirect,GFlags(A3) ; turn off bit
|
|
@Out
|
|
MOVEM.L (SP)+,D2/D3/A0/A1 ; restore all regs <1.8>
|
|
RTS ; return
|
|
|
|
ENDWITH
|
|
|
|
|
|
V8GrayScreen
|
|
;---------------------------------------------------------------------
|
|
;
|
|
; Fill the screen with a 50% dithered gray pattern. To have gotten here
|
|
; we must have had a valid display connected, so there are not tests
|
|
; for inactive displays here.
|
|
;
|
|
; D1 = spID of screen depth - FirstVidMode
|
|
; A3 = driver private storage
|
|
;
|
|
; All registers are preserved
|
|
;
|
|
|
|
WITH V8VidPrivates
|
|
|
|
MOVEM.L D0-D3/A0-A1,-(SP) ; save all registers
|
|
|
|
LEA V8Pats,A1 ; get a pointer to the pattern table
|
|
MOVE.L (A1,D1*4),D3 ; D3 = the proper pattern
|
|
|
|
MOVEQ.L #$17,D0 ; make a mask for pertinent bits
|
|
AND.B saveSlotId(A3),D0 ; get the monitor+upper option bit
|
|
|
|
CMP.B #sRsrc_Vid_V8_GSa**$17,D0 ; is it a standard Rubik?
|
|
BNE.S @0 ; if not, continue
|
|
LEA V8GSParms,A1 ;
|
|
BRA.S @Blast2
|
|
|
|
@0 CMP.B #sRsrc_Vid_V8_A2Ema**$17,D0 ; is it a Rubik in A// mode?
|
|
BNE.S @1 ; if not, continue
|
|
LEA V8A2Parms,A1 ;
|
|
BRA.S @Blast2
|
|
|
|
; if it's none of the above it's either a High-Res w/vRAM or a VGA which use the same parameters
|
|
|
|
@1 LEA V8HRvRAMParms,A1 ;
|
|
|
|
@Blast2
|
|
BTST #3,saveSlotID(A3) ; if this bit is cleared, then 512K vRAM
|
|
BNE.S @ItsOK ; if bit set, then 256K vRAM so parm addr is OK
|
|
; ¥¥¥!!!¥¥¥ ADDA #LongParmShift,A1 ; advance A1 to 512K parameters
|
|
ADDA #58,A1 ; advance A1 to 512K parameters
|
|
@ItsOK
|
|
MOVE.L saveBaseAddr(A3),A0 ; get the frame buffer base address
|
|
MOVE.W (A1)+,D0 ; get the # of rows
|
|
@NxtRow
|
|
MOVE.W (A1,D1*4),D2 ; get the # of longs/row
|
|
@NxtLong MOVE.L D3,(A0)+ ; write gray
|
|
DBRA D2,@NxtLong ; for each scanline
|
|
ADD.W 2(A1,D1*4),A0 ; add the skip factor for each line
|
|
NOT.L D3 ; invert pattern on next row
|
|
DBRA D0,@NxtRow ; for each row
|
|
|
|
MOVEM.L (SP)+,D0-D3/A0-A1 ; restore registers
|
|
RTS
|
|
|
|
|
|
V8Pats DC.L OneBitGray,TwoBitGray,FourBitGray,EightBitGray,SixteenBitGray
|
|
|
|
|
|
|
|
V8DirectCLUTSet
|
|
;---------------------------------------------------------------------
|
|
;
|
|
; V8DirectCLUTSet writes gamma-corrected ascending grayscale ramps into
|
|
; the CLUT
|
|
;
|
|
; A3 = dCtlStorage pointer
|
|
;
|
|
; Preserves all registers
|
|
;
|
|
;---------------------------------------------------------------------
|
|
|
|
MOVEM.L D0-D2/A0/A4-A6,-(SP) ; save a register
|
|
|
|
MOVE.L saveGammaPtr(A3),A0 ; get pointer to gamma data structure
|
|
MOVE.W GFormulaSize(A0),D0 ; get the size of formula data
|
|
LEA GFormulaData(A0),A4 ; point to formula data
|
|
ADD D0,A4 ; red correction table starts here
|
|
MOVE.L A4,A5 ; get default pointer to green data
|
|
MOVE.L A4,A6 ; get default pointer to blue data
|
|
CMP #1,GChanCnt(A0) ; if only only one table, we're set
|
|
BEQ.S @OneTbl ; => just one table
|
|
|
|
MOVE GDataWidth(A0),D1 ; get width of each entry in bits
|
|
ADD #7,D1 ; round to nearest byte
|
|
LSR #3,D1 ; get bytes per entry
|
|
MULU GDataCnt(A0),D1 ; get size of table in bytes
|
|
|
|
ADDA D1,A5 ; calc base of green
|
|
ASL #1,D0 ; mulu times 2
|
|
ADDA D1,A6 ; calc base of blue
|
|
|
|
@OneTbl
|
|
|
|
MOVE.L saveVDACBase(A3),A0 ; point to the hardware
|
|
ADDA #V8DACwDataReg,A0 ; point to data register
|
|
CLR.B V8DACwAddReg-V8DACwDataReg(A0) ; start at the beginning of CLUT
|
|
|
|
MOVE.W #$1F,D2 ; set up counter
|
|
|
|
MOVE.W SR,-(SP) ; preserve the status register
|
|
MOVEQ #7,D0 ; get mask in D0
|
|
AND.B (SP),D0 ; get the interrupt level
|
|
SUBQ.B #2,D0 ;
|
|
BGE.S @OK ; if ³, then don't change
|
|
ORI.W #$0200,SR ; raise above level-2
|
|
ANDI.W #$FAFF,SR ; make it level-2
|
|
@OK
|
|
|
|
; write an incrementing grayscale ramp
|
|
|
|
MOVEQ #0,D0 ; set up ramp start
|
|
|
|
@Repeat
|
|
MOVE.L D0,D1 ; copy the position pointer
|
|
SWAP D1 ; get the ÒintegerÓ part
|
|
MOVE.B (A4,D1),(A0) ; put red
|
|
MOVE.B (A5,D1),(A0) ; put green
|
|
MOVE.B (A6,D1),(A0) ; put blue
|
|
|
|
ADD.L #$00083900,D0 ; add 8 and 7/31 to the number
|
|
|
|
DBRA D2,@Repeat ;
|
|
|
|
MOVE (SP)+,SR ; restore the status reg
|
|
MOVEM.L (SP)+,D0-D2/A0/A4-A6 ; restore saved registers
|
|
RTS
|
|
|
|
|
|
|
|
;
|
|
; some simple screen size parameters. The first number is the number of scanlines to
|
|
; erase for each mode. The next numbers are in pairs. The first element of each pair is the number
|
|
; of longs to gray per scanline. The second element is the skip factor (number of bytes to skip
|
|
; to get to beginning of the next scanline). The second set of numbers are the same info for the
|
|
; 512K vRAM version (which has 1024 rowbytes rather than 512). There are more modes in the second
|
|
; set, but the code in V8GrayScreen knows how to deal with it
|
|
;
|
|
|
|
V8GSParms DC.W defmBounds_BGS-1
|
|
DC.W (((defmBounds_RGS*1)/8)/4)-1,(V8_512_RB-((defmBounds_RGS*1)/8))
|
|
DC.W (((defmBounds_RGS*2)/8)/4)-1,(V8_512_RB-((defmBounds_RGS*2)/8))
|
|
DC.W (((defmBounds_RGS*4)/8)/4)-1,(V8_512_RB-((defmBounds_RGS*4)/8))
|
|
DC.W (((defmBounds_RGS*8)/8)/4)-1,(V8_512_RB-((defmBounds_RGS*8)/8))
|
|
DC.W 0,0 ; pad out table
|
|
|
|
V8HRvRAMParms DC.W defmBounds_BHR-1
|
|
DC.W (((defmBounds_RHR*1)/8)/4)-1,(V8_512_RB-((defmBounds_RHR*1)/8))
|
|
DC.W (((defmBounds_RHR*2)/8)/4)-1,(V8_512_RB-((defmBounds_RHR*2)/8))
|
|
DC.W (((defmBounds_RHR*4)/8)/4)-1,(V8_512_RB-((defmBounds_RHR*4)/8))
|
|
DC.W 0,0 ; pad out table
|
|
|
|
V8A2Parms DC.W defmBounds_BA2Em-1
|
|
DC.W (((defmBounds_RA2Em*1)/8)/4)-1,(V8_512_RB-((defmBounds_RA2Em*1)/8))
|
|
DC.W (((defmBounds_RA2Em*2)/8)/4)-1,(V8_512_RB-((defmBounds_RA2Em*2)/8))
|
|
DC.W (((defmBounds_RA2Em*4)/8)/4)-1,(V8_512_RB-((defmBounds_RA2Em*4)/8))
|
|
DC.W 0,0 ; pad out table
|
|
|
|
V8GSParms_1024 DC.W defmBounds_BGS-1
|
|
DC.W (((defmBounds_RGS*1)/8)/4)-1,(V8_1024_RB-((defmBounds_RGS*1)/8))
|
|
DC.W (((defmBounds_RGS*2)/8)/4)-1,(V8_1024_RB-((defmBounds_RGS*2)/8))
|
|
DC.W (((defmBounds_RGS*4)/8)/4)-1,(V8_1024_RB-((defmBounds_RGS*4)/8))
|
|
DC.W (((defmBounds_RGS*8)/8)/4)-1,(V8_1024_RB-((defmBounds_RGS*8)/8))
|
|
DC.W (((defmBounds_RGS*16)/8)/4)-1,(V8_1024_RB-((defmBounds_RGS*16)/8))
|
|
|
|
V8HRvRAMParms_1024 DC.W defmBounds_BHR-1
|
|
DC.W (((defmBounds_RHR*1)/8)/4)-1,(V8_1024_RB-((defmBounds_RHR*1)/8))
|
|
DC.W (((defmBounds_RHR*2)/8)/4)-1,(V8_1024_RB-((defmBounds_RHR*2)/8))
|
|
DC.W (((defmBounds_RHR*4)/8)/4)-1,(V8_1024_RB-((defmBounds_RHR*4)/8))
|
|
DC.W (((defmBounds_RHR*8)/8)/4)-1,(V8_1024_RB-((defmBounds_RHR*8)/8))
|
|
|
|
V8A2Parms_1024 DC.W defmBounds_BA2Em-1
|
|
DC.W (((defmBounds_RA2Em*1)/8)/4)-1,(V8_1024_RB-((defmBounds_RA2Em*1)/8))
|
|
DC.W (((defmBounds_RA2Em*2)/8)/4)-1,(V8_1024_RB-((defmBounds_RA2Em*2)/8))
|
|
DC.W (((defmBounds_RA2Em*4)/8)/4)-1,(V8_1024_RB-((defmBounds_RA2Em*4)/8))
|
|
DC.W (((defmBounds_RA2Em*8)/8)/4)-1,(V8_1024_RB-((defmBounds_RA2Em*8)/8))
|
|
|
|
V8HRParms DC.W defmBounds_BHR-1
|
|
DC.W (((defmBounds_RHR*1)/8)/4)-1,(OBMHRRB-((defmBounds_RHR*1)/8))
|
|
|
|
LongParmShift EQU V8GSParms_1024-V8GSParms
|
|
|
|
ENDWITH
|
|
|
|
|
|
;-------------------------------------------------------------
|
|
; The Interrupt handler for the Elsie Built-In Video
|
|
;-------------------------------------------------------------
|
|
; On entry A1 contains the pointer to the driver's private storage
|
|
; D0-D3/A0-A3 have been preserved.
|
|
|
|
|
|
V8BeginIH
|
|
|
|
MOVE.L V8,A0 ; point to the VISA chip
|
|
MOVE.B #$40,V8SInt(A0) ; clear the interrupt
|
|
CLR.W D0 ; set slot zero in D0
|
|
|
|
MOVE.L JVBLTask,A0 ; call the VBL task manager
|
|
JSR (A0) ; with slot # in D0
|
|
|
|
@Done
|
|
MOVEQ #1,D0 ; signal that int was serviced
|
|
RTS ; and return to caller
|
|
|
|
END |