mac-rom/DeclData/DeclVideo/Civic/CivicDriver.a

5165 lines
204 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;
; File: CivicDriver.a
;
; Contains: This file contains the video driver for use by the Macintosh
; OS for the Civic hardware.
;
; Written by: Mike Puckett/Fernando Urbina, March 2, 1992.
;
; Copyright: © 1992-1993 by Apple Computer, Inc. All rights reserved.
;
; Change History (most recent first):
;
; <SM18> 8/12/93 BG Changed various Cyclone-related boxflags to their official
; names.
; <SM17> 08-03-93 jmp Changed the reference names of the multiscan display constants
; to their new names.
; <16> 7/2/93 IH #1096920: Slot Manager not correctly updated in set resolution
; call.
; <SM15> 6/14/93 kc Roll in Ludwig.
; <LW19> 6/9/93 fau Fixed two bugs (not in radar): When aborting SetRGBBypass from
; composite to RGB, I was switching the MMC_Bypass bit and not
; restoring it if we aborted. I now don't switch it until after
; we know the switch happenned. This will drive bad timing into
; the composite display for a little bit. Also, in the dynamic
; switch, I was not checking whether the new spID supported
; video-in in 16bpp. If it didn't and the current VidInMode was
; in that depth, we would crash. Now, after checking that the
; current graphics mode is supported, we check that the new spID
; supports 16bpp and if not, if the current vidinmode is 16bpp we
; bail out, returning an 8 as a word in the parameters.
; <LW18> 6/4/93 fau Fixed bug #1089549: Cyclone allos switch to RGB Monitor when
; booted on TV. I was not updating my NTSCTimingON and my
; ConvolutionON flags when first opening the driver.
; <LW17> 5/14/93 fau Fixed bugs: #1083318, #PUMA, #1084366: Problem with VideoReset,
; saveVidInMode.
; <LW16> 5/3/93 fau Fixed a problem in SetDepth (again?) where I was using D1 and
; then calling dWrite_Civic, which uses D1. This was causing D1
; to enable VDC interrupts when they shouldn't have.
; <LW15> 5/1/93 mal Actually (fau): Reverted change in SetVidInModeGuts where I was
; getting #BusSize off the video parameters, but in some cases,
; it's not right. Force it to 0 as it was in <LW13>.
; <LW14> 4/30/93 fau Two Bug Fixes: In video-in grayscale, I was setting the
; big-small bit when the size was > 512. It should never be set
; for grayscale. Also, it shouldn't have been 512 wide for
; changing that bit, it is 496. Also, removed Wait2000ms, which
; is not used. Finally, added a table to translate the multisync
; spID to a monID so that I can determine the video-in sizes that
; are supported by the current spID. That algorithm was monID
; based, so I translate the spID when it's a multisync display.
; <SM14> 4/29/93 fau Synchronized with Ludwig.
; <LW13> 4/14/93 fau Fixed a bug in GetCompCapabilities where I was still looking at
; the 2MegVRAM byte, that doesn't exist anymore.
; <LW12> 4/14/93 fau Changes to fix the video-flashing bugs; re-architected the way
; video-in works in Civic. Now it's always enabled, except when
; you go to a mode that doesn't support it; LOTS of changes due
; to that, in any calls that do video-in. Disabled overlay while
; graying screen. Added support for the new Display Manager.
; <SM13> 4/6/93 fau Another synchro with Ludwig.
; <LW11> 4/5/93 fau Approved by Change Control Board: Moved the video-in calls to
; be in the private area, instead of the public area. They should
; not really be public. Added a Set/GetSync call to support the
; "green" monitors.
; <SM12> 4/5/93 chp Synchronize with Ludwig.
; <LW10> 4/4/93 fau Fixed bug #1074831: Boundary check SetEntries for
; csStart+csCount > ccRange.
; Fixed bug #1056748: GetVidInMode not returning correct
; csBaseAddr: Problem with using the wrong record for the call.
; Fixed bug #1074829: GetVideoIn reports inverted PRAM bit. I
; wasn't inverting the value of what I read from PRAM!
; Fixed bug #1074815: SetRGBBypass does not return -17. True, I
; was returning a good error code when the routine couldn't do
; it!
; Fixed bug #1074849: In SetRGBBypass, when switching back from
; compostie to a mono only device, I was overwriting the gFlags
; where i had set the isMono and Gray bits.
; <LW9> 3/24/93 fau Added a SetVideoCLUT routine to write the current gamma table to
; the video-in CLUT. It is called by SetGamma, as well as by
; SetVideoInMode.
; <LW8> 2/17/93 fau Fixed a trashing of D1 (saved D0 and restored D1) in the VBL
; handler routine.
; <LW7> 2/17/93 fau Reversed the bits in the GetVideoIn call to reflect the original
; intent: Bit 0 says whether video-in is enabled or not. Bit 1
; whether the PRAM bit is set or not.
; <LW6> 2/16/93 fau Fixed lots of bugs: Allow color video-in when in a FullPage
; monitor. Added a new status call GetCompOutCapab to give us
; details about the equivalend video-out spid's for different
; monitors. Added support for Clifton so that we can switch to
; video-out. Changed the bits in GetVideoIn so that it matches
; SetVideoIn. Revamped the RGBBypass call.
; <LW5> 1/28/93 KW (SM11 kc) Rename equate (alpha to xalpha) to avoid name
; collision. (We should use records instead of an equates to avoid
; the problem).
; <SM11> 1/25/93 kc Rename equate (alpha to xalpha) to avoid name collision. (We
; should use records instead of an equates to avoid the problem).
; <LW4> 1/8/93 FU Removed the debugstrings for the A9 build and changed the
; polarity of the check for the VDC interrupt, per new information
; telling us that it is active low.
; <LW3> 1/4/93 fau Lots of cleanup: Removed support for 24-bit MMU support.
; Changed MMC to YMCA references. Moved the VidInPrivates to the
; regular privates. Initialized SetVidInMode to 8bpp in VidOpen.
; Made the dispatch of private selectors be jump-table based.
; Revamped Set/GetVideoIn to fully support dynamic switching and
; non-dynamic switching.
; <LW2> 12/18/92 fau Fixed a bug where I was checking for a nil vidinrect: I was not
; doing correctly (using D0 for 2 sides and D2 for the other
; ones!).
; <SM10> 12/8/92 fau In the DynamicSwitch routine, fixed two bugs, where I was not
; updating the GFlags to indicate that video-in was/wasn't enabled
; and whether the mode was isDirect or not. This fixed a problem
; with the CLUT not being updated when switching dynamically from
; Thousands to 256.
; <SM9> 11/10/92 fau Fixed a bug in ChkMode where we were not generating the right
; offset for the 1/2Meg VRAM check: (a0,d0),d0 is really a word
; offset of a0; the code assumed a byte offset.
; <SM8> 11/6/92 fau Added code to the VBL/VDC interrupt handler to take care of any
; spurious VDC interrupts (VDC interrupts occuring when it is not
; enabled). Also, added a temporary Debugger string in the
; handler for when it gets called an no VBL's or VDC's are
; hapenning.
; <SM7> 11/2/92 kc Don't include SonicEqu.a.
; <SM6> 10/30/92 fau Move the vidinrect in the previous checkin to 2 clocks after
; HFP/VFP
; <SM5> 10/29/92 fau Added support for booting off composite by setting a PRAM bit.
; (A new control/status call). Made sure the vidin rect is out in
; right field when the private's savevidin... are all zero.
; <SM4> 10/28/92 SWC Changed VideoEqu.a->Video.a and ShutdownEqu.a->Shutdown.a.
; <SM3> 10/22/92 fau Changed MMCAddr to DecoderAddr.
; <SM2> 10/8/92 fau Fixed bug in GetGamma where I was moving a byte instead of a
; long into the address increment register for the main loop.
; <1> 10/6/92 GDW New location for ROMLink tool.
; <SM10> 9/30/92 fau Changed the use of VDACAddr to SebastianAddr.
; <SM9> 8/27/92 fau Got rid of support for early Civic Rev's. Added a private call
; at $85 to reprogram Civic with new parameters (this is
; temporary).
; <SM8> 7/28/92 fau Fixed a problem in SetRGBBypass where the interrupt level was
; not being saved/restored before calling CivicWaitForVSync.
; Moved the enable of Casio in that routine to a more proper
; place.
; <SM7> 6/30/92 fau Fixed the setting of the NTSCTimingON flag in SetRGBBypass, and
; the return of that flag in GetRGBBypass.
; <SM6> 6/26/92 fau Fixed the problem that existed when changing monitor depths and
; displaying video-in (the video-in parameters would get trashed).
; Same deal with switching to composite out.
; <SM5> 6/19/92 KW (fau,P13) Lots of stuff. In the interrupt handler routine, I'm
; now checking Civic's VBL_INT register, instead of the VDC_INT.
; Disabled overlay in SetVidMode. Added the Set/GetRGBBypass
; routines. Compacted the new cs codes, getting rid of the ones
; we decided to get rid off. Installed the VBL with a priority of
; 255, instead of 0. Got rid of the baseaddress in the VidParams,
; so now I get it from the s-resource. Check for Civic II and new
; oscillators. Added padding and a couple new parameters to
; CivicVidPrivates. Whew...
; <SM4> 6/18/92 KW (fau, P12) Fixed bug in determining whether to program Civic to
; use a big/small video-in size. (Moved a byte instead of a
; word). Also, added this size check to video-in 8bpp (before I
; only checked on 16bpp). Finally, changed the video-in monitor
; support table to check whether a VGA family mode is SxVGA which
; will not support 16bpp video-in, whereas the other VGA modes do.
; <SM3> 6/4/92 KW (jmp,P11) Slightly optimized & improved the soon-to-obsolete
; Civic vs. Civic2 checking code.
; (fau,P10) Added a new dCivicIIRegTable that has the extra bit
; defined for Rowwords and also the DoubleLine register (1 bit)
; tacked at the end of the table. Modified dGetCivicReg in a
; brute force manner to check which Civic it's running on and load
; the appropriate table.
; (fau,P9) Added a WaitforVBL and extended the reset pulse to
; Civic after changing horizontal display parameters. This was
; needed to make sure Civic was programmed correctly when using
; slow displays (i.e. NTSC).
; (fau,P8) Fixed bug in CivicDirectCLUTSet where D5 wasn't cleared
; before Bset'ing #useTrans.
; (fau,P7) Added alpha channel support for Set/GetEntries and
; SetVidMode, so the alpha channel is not blown away if video-in
; is enabled.
; <SM2> 5/29/92 kc Fix Assembler warnings.
; <P6> 5/1/92 fau Something went wrong in the database for <P5>, so I'm checking
; it in again to fix it.
; <P5> 5/1/92 fau Fixed Bug in SetVidInRect where I was blowing away saveBaseAddr.
; <P4> 5/1/92 fau Lots of stuff for Video-in support: Added CivicVidInPrivates
; table. Added stubs for all the new status calls. Added the
; SetVidInMode, SetVidInRect and SetFieldInterrupt control calls
; and stubs for the others. Added a temporary handling of the
; Field interrupt to CivicBeginIH.
; <P3> 04/13/92 jmp Optimized the SetDepth routine slightly, revised some comments,
; and changed GrayScreen to reflect the current vidParams data.
; <P2> 03/24/92 jmp Optimized the Interrupt Handler and the WaitVSync routines,
; re-ordered the way various parameters get changed in the
; SetDepth code, and fixed a bug where I was not returning the
; correct base address in various Control/Status calls.
; <1> 03/04/92 jmp first checked in
STRING C
PRINT OFF
LOAD 'StandardEqu.d'
INCLUDE 'HardwarePrivateEqu.a'
INCLUDE 'ROMEqu.a'
INCLUDE 'Video.a'
INCLUDE 'SlotMgrEqu.a'
INCLUDE 'UniversalEqu.a'
INCLUDE 'DepVideoEqu.a' ; <LW14>
PRINT ON ; <LW14>
SEG '_sCivicDriver'
BLANKS ON
STRING ASIS
MACHINE MC68020
; This is device storage which is stored in the dCtlStorage field of the AuxDCE.
CivicVidPrivates 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
saveVidPtr Ds.L 1 ; the pointer to the vidParams block
saveVDACBase DS.L 1 ; the base addr of the VDAC
saveCivicBase DS.L 1 ; the base addr of Civic
gFlags DS.W 1 ; flags word (hi-order byte, actually)
scratch Ds.l 1 ; scratch register
saveMode DS.W 1 ; the current mode setting
saveVidInMode DS.W 1 ; the current video-in mode (8 or 16 bpp)
saveMonID DS.W 1 ; monitor type ID
saveSlotId DS.B 1 ; spID of video sRsrc
saveRGBSlotId DS.B 1 ; The screen base address of the 2nd Vid Ptr
saveSizeVRAM DS.B 1 ; amount of vRAM (0=1Meg,1=2Meg)
saveBoxFlag DS.B 1 ; The box flag for the machine we're running on
saveYMCABaseAddr DS.L 1 ; The MMC Base adress
save2ndVidPtr DS.L 1 ; A second vidParams ptr to toggle between RGB / Comp sync
saveVidInSize DS.W 1 ; VidInSize (1 for > 496 pixels in 16bpp <LW14>
saveVinVAL DS.W 1 ; VinVAL for the Video In VRAM
saveVinVFP DS.W 1 ; VinVFP for the Video In VRAM
saveVinHAL DS.W 1 ; VinHAL for the Video In VRAM
saveVinHFP DS.W 1 ; VinHFP for the Video In VRAM
saveVinHFPD DS.W 1 ; VinHFPD for the Video In VRAM
currentTop DS.W 1 ; Top of the current VidInRect
currentLeft DS.W 1 ; Left of the current VidInRect
currentBottom DS.W 1 ; Bottom of the current VidInRect
currentRight DS.W 1 ; Right of the currentVidInRect
saveNewBaseMode Ds.w 1 ; Mode at which the base address changes from a 0 offset to a non-zero offset
saveBaseAddrOffset Ds.l 1 ; The offset to add to the base address when the mode is saveNewBaseMode or higher
VDCCLkState Ds.w 1 ; State of the VDC clock before disabling video-in
VDCEnbState Ds.w 1 ; State of the VDC Interrupt enable bit before disabling video-in
OverlayState Ds.w 1 ; State of the Overlay bit in Sebastian before disabling video-in
CivicVidPrivSize EQU *
ENDR
CivicFrame Record {A6Link},Decrement
Return DS.L 1 ; Return address.
A6Link DS.L 1 ; Saved A6.
spBlk DS SPBlock ; SpBlock for generic use.
sPRAMBlk DS.B SizeSPRAMRec ; sPRAMRec for generic use.
civicBaseAddr DS.L 1 ; Pointer to CivicÕs base address.
mmcBaseAddr DS.L 1 ; Pointer to MMCÕs base address.
vRAMBaseAddr DS.L 1 ; Pointer to base of vRAM.
vidParamsPtr DS.L 1 ; Pointer to video parameters.
configParamsPtr DS.L 1 ; Pointer to config parameters.
savedMMUMode DS.B 1 ; All Civic regs must be 32-bit addressed.
spFlags DS.B 1 ; Local copy of slot pRAM flags byte.
CFSize Equ *
Endr
LCivicDriver MAIN EXPORT
;-------------------------------------------------------------------
; Video Driver Header
;-------------------------------------------------------------------
;
CivicVidDrvr
DC.W $4C00 ; ctl,status,needsLock
DC.W 0,0,0 ; not an ornament
; Entry point offset table
DC.W CivicVidOpen-CivicVidDrvr ; open routine
DC.W CivicVidDrvr-CivicVidDrvr ; no prime in normal video drivers
DC.W CivicVidCtl-CivicVidDrvr ; control
DC.W CivicVidStatus-CivicVidDrvr ; status
DC.W CivicVidClose-CivicVidDrvr ; close
STRING Pascal
CivicVidTitle
DC.B '.Display_Video_Apple_Civic'
ALIGN 2 ; make sure we're aligned
DC.W CurCivicDrvrVersion ; current version
STRING ASIS
;
; CivicCLUTTbl 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. This is required because, in 1-4bpp, the
; entries are distributed throughout the CLUT address space. As a result, we use sequential CLUT mode
; ONLY in 8/16bpp modes. 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)
CivicCLUTTbl
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
DC.B $1F,$00,$00,$01 ; for sixteen-bit mode
DC.B $FF,$00,$00,$01 ; for thirty-two-bit mode
CivicCLUTRec RECORD 0 ;
ccRange DS.B 1 ; maximum index value in this depth
ccStart DS.B 1 ; lowest active CLUT address
ccSkip DS.W 1 ; skip value between active addresses
CivicCLUTSize Equ *
ENDR
;
; These are the bit patterns for grays in each depth
;
CivicPats Dc.l OneBitGray,TwoBitGray,FourBitGray,EightBitGray
Dc.l SixteenBitGray,ThirtyTwoBitGray
;
; Normally, if a type-6 is detected on boot, PrimaryInit just sets up for a Hi-Res. However,
; if the alternate-sense pRam code is valid, then we set things up as if the monitor code
; specified in pRam were actually connected. The CivicMonIDs table (below) is composed
; of the valid monitor IDs supported by Civic.
;
CivicMonIDs Dc.w CMonIDsEnd-CMonIDsBegin-1-1 ; -1 for assember warning pad
CMonIDsBegin
Dc.b indexedSenseRGB2P,indexedSenseFP,indexedSenseRubik,indexedSense2P
Dc.b indexedSenseNTSC,indexedSenseRGBFP,indexedSenseHR
Dc.b extendedSensePALBox,extendedSenseNTSC,extendedSenseVGA
Dc.b extendedSenseGF,extendedSensePAL,extendedSense19
DS.B 1 ; assember warning pad
CMonIDsEnd
Align 4
; Civic has a 1-bit wide interface, but many of its registers logically consist of up to 12-bits.
; The following table is the instantiation of the CivicRecord defined in DepVideoEqu.a. Each entry
; consists of two fields. The first field is the offset (from the Civic base address) to
; the least significant bit (long-word aligned) of a particular Civic register. The second
; field is the logical size of the Civic register. This table is used by the GetCivicRegister
; routine defined above. Eventually, this table should probably be moved into a Slot Resource
; for better updating between the PrimaryInit and driver code that must use it.
;
dCivicRegTable
Dc.w $000,01,$004,01,$008,01,$00C,01,$010,01,$014,01,$018,01,$01C,01,$020,03
Dc.w $02C,01,$040,01,$044,02,$04C,01,$050,01,$054,01,$058,01,$05C,01,$060,01
Dc.w $064,01,$068,01,$06C,01,$080,03,$08C,08,$0C0,09,$100,01,$104,01,$108,01
Dc.w $10C,01,$110,01,$114,01,$118,01,$11C,01,$120,01,$124,01,$128,01,$12C,01
Dc.w $140,12,$180,12,$1C0,12,$200,02,$240,12,$280,12,$2C0,08,$300,12,$340,12
Dc.w $380,12,$3C0,12,$400,12,$440,10,$480,12,$4C0,12,$500,12,$540,12,$580,12
Dc.w $5C0,12,$600,12,$640,12,$680,12,$6C0,12,$208,1
Align 4
; This is the Video-In maximum rectangle capabilities for 1Meg and 2Meg VRAM configurations
CVidInBPPRec RECORD 0
cVidInMaxH DS.W 1 ; Maximum Horizontal Value
cVidInMaxV DS.W 1 ; Maximum Vertical Value
CVidInBPPRecSize EQU *
ENDR
With CVidInBPPRec
CVidInVRAMRec RECORD 0
c8bppMax DS.B CVidInBPPRecSize ; MaxH/MaxV for 8bpp
c16bppMax DS.B CVidInBPPRecSize ; MaxH/MaxV for 16bpp
CVidInVRAMRecSize EQU *
ENDR
EndWith
With CVidInVRAMRec
CivicVidInRec RECORD 0
cVidIn1MegVRAM DS.b CVidInVRAMRecSize ; The MaxH/MaxV for 8pbb and 16pbb for a 1 Meg VRAM
cVidIn2MegVRAM DS.b CVidInVRAMRecSize ; The MaxH/MaxV for 8pbb and 16pbb for a 2 Megs VRAM
CivicVidInRecSize EQU *
ENDR
EndWith
Align 4
; The CivicVidInTable is an array of parameters indexed by display type. Each display type has
; 2 sets of parameters: One set for a 1 Meg VRAM configuration, and the other for a 2 Meg VRAM
; configuration. The parameters in each set consist of the maximum allowable width and height
; for 8bpp and 16 bpp. There are two special cases:
;
; 1. If the Maxh/MaxV values are both 0, that bpp depth is not supported on that monitor.
; 2. If the MaxH/MaxV values are both -1, that bpp depth is supported, but not at full PAL size.
; The SetVidInRect will need to calculate the maximum V, given an H. The size is limited by the
; amount of VRAM that is installed.
;
; This table assumes that the maximum video in window to be displayed is FF PAL: 768,576
With CivicVidInRec
CivicVidInTable
; 8bpp 16bpp
CVidInVesuvioTbl Dc.w 768,576, 0,0
Dc.w 768,576, 0,0
CVidInFullPageTbl Dc.w 640,576, -1,-1
Dc.w 640,576, 640,576
CVidInRubikTbl Dc.w 512,384, 512,384
Dc.w 512,384, 512,384
CVidInKongTbl Dc.w 768,576, 0,0
Dc.w 768,576, 0,0
CVidInNTSCTbl Dc.w 640,480, -1,-1
Dc.w 640,480, 640,480
CVidInRGBFullPageTbl Dc.w 640,576, -1,-1
Dc.w 640,576, 640,576
CVidInHiResTbl Dc.w 640,480, -1,-1
Dc.w 640,480, 640,480
CVidInNoConnectTbl Dc.w 0,0, 0,0
Dc.w 0,0, 0,0
CVidInVGATbl Dc.w 768,576, -1,-1 ; Might get clipped if in VGA (640x400) mode.
Dc.w 768,576, 768,576 ; Might get clipped if in VGA (640x400) mode.
CVidInPALTbl Dc.w 768,576, -1,-1
Dc.w 768,576, 768,576
CVidInGoldFishTbl Dc.w 768,576, -1,-1
Dc.w 768,576, 768,576
CVidIn19Tbl Dc.w 768,576, 0,0
Dc.w 768,576, 0,0
EndWith
; The following table is used by the SwitchMode call to determine two things. First,
; it must decide whether the requested mode to switch to is valid or not. If
; the requested mode is not in the SwitchTable, the call will fail. Also, even
; if the requested mode is in table, if the current bit depth is too large
; for the requested mode, SwitchMode must still fail.
;
SwitchTable1Meg
Dc.b sRsrc_Vid_Civic_viHRa,FifthVidMode ; Hi-Res (1 Meg)
Dc.b sRsrc_Vid_Civic_viHRNTSCST,SixthVidMode ; Hi-Res 512x384 (1-2 Meg)
Dc.b sRsrc_Vid_Civic_viHR400, SixthVidMode ; Hi-Res 640x400 (1-2 Meg)
Dc.b sRsrc_Vid_Civic_viGFPALFFa, FifthVidMode ; GoldFish 768x576 (1 Meg)
Dc.b sRsrc_Vid_Civic_viSVGA72a, FifthVidMode ; SuperVGA 800x600 (1 Meg)
Dc.b sRsrc_Vid_Civic_viGFa, FifthVidMode ; GoldFish (1 Meg)
Dc.b sRsrc_Vid_Civic_vi19a, FourthVidMode ; 19" (1024x768) (1 Meg)
Dc.b sRsrc_Vid_Civic_vi2PRGBa, FourthVidMode ; Vesuvio (1 Meg)
Dc.b 0,0
SwitchTable2Meg
Dc.b sRsrc_Vid_Civic_viHRb,SixthVidMode ; Hi-Res (2 Meg)
Dc.b sRsrc_Vid_Civic_viHRNTSCST,SixthVidMode ; Hi-Res 512x384 (1-2 Meg)
Dc.b sRsrc_Vid_Civic_viHR400, SixthVidMode ; Hi-Res 640x400 (1-2 Meg)
Dc.b sRsrc_Vid_Civic_viGFPALFFb, SixthVidMode ; GoldFish 768x576 (2 Meg)
Dc.b sRsrc_Vid_Civic_viSVGA72b, SixthVidMode ; SuperVGA 800x600 (2 Meg)
Dc.b sRsrc_Vid_Civic_viGFb, SixthVidMode ; GoldFish (2 Meg)
Dc.b sRsrc_Vid_Civic_vi19b, FifthVidMode ; 19" (1024x768) (2 Meg)
Dc.b sRsrc_Vid_Civic_vi2PRGBb, FifthVidMode ; Vesuvio (2 Meg)
Dc.b 0,0
; The following table returns what the indexedSese is for a particular spID that is in the <LW14>
; Multisync familymode. <LW14>
; <LW14>
EquivalendMonIDTable ; <LW14>
Dc.b sRsrc_Vid_Civic_viHRa,indexedSenseHR ; Hi-Res (1 Meg) <LW14>
Dc.b sRsrc_Vid_Civic_viHRb,indexedSenseHR ; Hi-Res (2 Meg) <LW14>
Dc.b sRsrc_Vid_Civic_viHRNTSCST,indexedSenseHR ; Hi-Res 512x384 (1-2 Meg) <LW14>
Dc.b sRsrc_Vid_Civic_viHR400, indexedSenseHR ; Hi-Res 640x400 (1-2 Meg) <LW14>
Dc.b sRsrc_Vid_Civic_viGFPALFFb, indexedSenseGF ; GoldFish 768x576 (1 Meg) <LW14>
Dc.b sRsrc_Vid_Civic_viSVGA72b, indexedSenseVGA ; SuperVGA 800x600 (1 Meg) <LW14>
Dc.b sRsrc_Vid_Civic_viGFa, indexedSenseGF ; GoldFish (1 Meg) <LW14>
Dc.b sRsrc_Vid_Civic_vi19a, indexedSense19 ; 19" (1024x768) (1 Meg) <LW14>
Dc.b sRsrc_Vid_Civic_vi2PRGBa, indexedSenseRGB2P ; Vesuvio (1 Meg) <LW14>
Dc.b sRsrc_Vid_Civic_viGFPALFFb, indexedSenseGF ; GoldFish 768x576 (2 Meg) <LW14>
Dc.b sRsrc_Vid_Civic_viSVGA72b, indexedSenseVGA ; SuperVGA 800x600 (2 Meg) <LW14>
Dc.b sRsrc_Vid_Civic_viGFb, indexedSenseGF ; GoldFish (2 Meg) <LW14>
Dc.b sRsrc_Vid_Civic_vi19b, indexedSense19 ; 19" (1024x768) (2 Meg) <LW14>
Dc.b sRsrc_Vid_Civic_vi2PRGBb, indexedSenseRGB2P ; Vesuvio (2 Meg) <LW14>
Dc.b 0,0 ; <LW14>
Align 4
**********************************************************************
*
* VidOpen allocates private storage for the device in the AuxDCE and locks
* it down for perpetuity. Also, it installs the interrupt handler and enables
* the (VBL) interrupts.
*
* Entry: A0 = param block pointer
* A1 = AuxDCE pointer
*
* Locals: A3 = pointer to private storage
*
* D0/D2 used as scratch
*
**********************************************************************
WITH VDPageInfo,SlotIntQElement,CivicVidPrivates
CivicVidOpen
;
; Allocate private storage (since block is CLEAR, GFlags are zeroed) and get
; a pointer to it in A3.
;
Move.l a4,-(Sp) ; save our scratch register
MOVEQ #CivicVidPrivSize,D0 ; get size of parameters
_ResrvMem ,SYS ; make room as low as possible
MOVEQ #CivicVidPrivSize,D0 ; get size of parameters
_NewHandle ,SYS,CLEAR ; get some memory for private storage
BNE @OpError1 ; => return an error in open
MOVE.L A0,dCtlStorage(A1) ; save returned handle in AuxDCE
_HLock ; and lock it down forever
MOVE.L (A0),A3 ; get pointer to privates in A3
;
; Remember the VDAC, Civic, and framebuffer base addresses since they're non-trivial to
; look up.
;
WITH ProductInfo,DecoderInfo,VideoInfo
MOVE.L UnivInfoPtr,A0 ; get a pointer to universal data
Move.b ProductKind(A0),saveBoxFlag(A3) ; Save this machine's boxflag
ADDA.L DecoderInfoPtr(A0),A0 ; point to the base address table
MOVE.L SebastianAddr(A0),saveVDACBase(A3) ; save VDACÕs base address
Move.l CivicAddr(A0),saveCivicBase(A3) ; save CivicÕs base address
Move.l DecoderAddr(A0),saveYMCABaseAddr(A3) ; Save YMCAÕs base address.
MOVE.L UnivInfoPtr,A0 ; get a pointer to universl data
ADDA.L VideoInfoPtr(A0),A0 ; point to the VideoInfo record
MOVE.L VRAMLogAddr32(A0),saveBaseAddr(A3) ; save base address too
ENDWITH
;
; 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 the Z-bit cleared.
MOVEQ #sqHDSize,D0 ; allocate a slot queue element
_NewPtr ,SYS,CLEAR ; get it from system heap cleared
BNE @OpError2 ; if not allocated, return bad
MOVE.L A0,saveSQElPtr(A3) ; save the SQ element pointer.
BSR CivicEnableVGuts ; do it
BNE @OpError2 ;
;
; Load the default gamma table from the slot resource list.
;
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
CLR.B spExtDev(A0) ;
_sRsrcInfo ; get the spsPointer
BNE @OpError3 ; if failed, then quit.
MOVE.B #sGammaDir,spID(A0) ; look for the gamma directory
_sFindStruct ; get that baby
BNE.S @DoLinear ; if failed, then do linear
MOVE.B #128,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 gamma 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 #0,D0 ; round it off
MOVE.L D0,saveGammaPtr(A3) ; put it in private storage
Bra.s @VidParams ; Jump around linear code.
;
; 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 @OpError3 ; 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 #drHwCivic,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.
;
; Get a pointer to the video hardware setup parameter block. Use this functional spID's spsPointer
; found above in the gamma section.
;
@VidParams
Move.l Sp,A0 ; Point to the spBlock on the stack.
Clr.w spID(A0) ; Start looking at spID 0, no external devices.
Clr.b spTBMask(A0) ; Only look for the board sRsrc.
Move.w #catBoard,spCategory(A0) ; Look for: catBoard,
Move.w #typBoard,spCType(A0) ; typBoard,
Clr.w spDrvrSW(A0) ; 0,
Clr.w spDrvrHW(A0) ; 0.
Clr.l spParamData(A0) ; (The board sRsrc must be enabled.)
Bset #foneslot,spParamData+3(A0) ; Limit search to slot 0.
_GetTypeSRsrc ; Get the spsPointer.
Bne @OpError4 ; If failed, quit.
MOVE.B #sVidParmDir,spID(A0) ; look for the video parameters dir
_sFindStruct ; Try to load it.
Bne @OpError4 ; If failed, quit.
MOVE.B dCtlSlotId(A1),spID(A0) ; look in the directory for this config's parameters
_sGetBlock ; Try to load it.
Bne @OpError4 ; If failed, quit.
MOVE.L spResult(A0),saveVidPtr(A3) ; get pointer to it
_sFindDevBase ; Get the base address for this spID
Move.l spResult(A0),D0 ; and save it in.
Move.l D0,saveBaseAddr(A3) ; our privates. This is the base of active video.
; Now, look for the mode at which the vpBaseOffset changes from non-zero to 0, and save it in our privates.
WITH VPBlock
Move.w #SixthVidMode,D1 ; Start at 32bpp
@LookForOffset
Move.b dCtlSlot(A1),spSlot(A0) ; Look at this slot
Clr.b spExtDev(A0) ; and no ExtDev
Move.b dCtlSlotID(A1),spID(A0) ; Put spID into spBlock.
_SRsrcInfo
Bne @OpError4 ; If failed, quit.
Move.b D1,spID(A0) ; Look for this mode
_SFindStruct
Beq.s @ModeExists ; If noErr, then get block
Cmp.w #-330,D0 ; Did we get a smBadRefID
Bne @OpError4 ; No, then quit.
Subi.w #1,D1 ; Look for next lower mode
bra.s @LookForOffset ;
@ModeExists
Move.b #mVidParams,spID(A0) ; Look for the video-parameters block
_SGetBlock
Bne @OpError4 ; If failed, quit.
Move.l spResult(A0),a4 ; save the pointer to the block
Move.L vpBaseOffset(A4),d0 ; Get Offset
Beq.s @GotOffset ; If zero, then we have our offset stored in privates
Move.l d0,saveBaseAddrOffset(A3) ; Store non-zero offset in our privates
DBRA d1,@LookForOffset ; look at next lower mode
@GotOffset
Addi.w #1,d1 ; Adjust mode that has the non-zero offset
move.w d1, saveNewBaseMode(A3) ; and save it in our privates
ENDWITH
;
; At PrimaryInit time, we used the sense lines to determine the type of display attached. For extended
; sense displays, we just mapped them to the end of indexed-sense displays. Since the gamma-correction
; code uses the monitor ID to determine if the passed-in table is applicable, we need to know the ÒrealÓ
; monitor ID. At PrimaryInit time, we store the real monitor ID in slot pRAM. So, we extract that
; information out here. Also, it should be noted that it would actually be inappropriate for us
; to re-read the sense-lines now, in that someone could potentially change/unplug the attached
; display between PrimaryInit and VidOpen, and that would cause us all sorts of havoc.
;
With SP_Params
Move.l Sp,A0 ; Point to spBlock on the stack.
Move.b dCtlSlot(A1),spSlot(A0) ; Put slot into spBlock.
Suba #sizeSPRamRec,Sp ; Allocate an SPRam block on the stack.
Move.l Sp,spResult(A0) ; Point to it.
_SReadPRAMRec ; Read Slot PRam.
Bne @OpError5 ; If failed quit.
Moveq #0,D2 ; Clear D2.w.
Move.b SP_MonID(Sp),D2 ; Get the monID (itÕs byte sized).
Move.b SP_Flags(Sp),D1 ; Get the flags byte so we can use it later <LW18>
Adda #sizeSPRamRec+spBlockSize,Sp ; Clean up the stack.
EndWith
;
; Say whether video-in is enabled by reading the bus_size register
Move.l saveCivicBase(A3),A0 ; Get Civic's base address
Move.l Civic_BusSize(A0),D0 ; Read the bus size bit
Btst #0,D0 ; (0 = video-in enabled, 1 = video-in disabled)
Bne.s @TestForComposite ; if 1, then leave bit in GFlags off
Bset #videoInEnb,GFlags(A3) ; Say we have video-in enabled
@TestForComposite
; Check to see if we're driving composite out
With CivicRecord,CivicVidParams ; <LW18>
; <LW18>
Move.l Civic_SyncClr(A0),D0 ; Initially If SyncClr == 1, then DB15, else Composite (reads inverted)
Btst #0,D0 ; Bit 0 has the actual data
bne.s @Bookkeeping ; carry on
Move.w gFlags(a3),d0 ; Get the flags _word_
Bset #CompositeSyncOn,d0 ; Say we are driving composite
Move.l saveVidPtr(A3),a0 ; Take a look at our privates <LW18>
Tst.b cvpConvEnb(A0) ; Get our convolution flag <LW18>
Beq.s @NoConvolution ; we are not driving convolution <LW18>
Bset #ConvolutionOn,d0 ; say we are indeed driving convolution <LW18>
@NoConvolution ; <LW18>
Btst #spCompOutPAL,D1 ; Were we driving PAL out <LW18>
Bne.s @DoingPAL ; if 1, then yes, it's PAL <LW18>
Bset #NTSCTimingOn,d0 ; say we are driving NTSC <LW18>
@DoingPAL ; <LW18>
Move.w d0,GFlags(a3) ; and save our GFlags that changed
;
; Do a little bookkeeping, etcÉ
;
@Bookkeeping
Move.w #8,saveVidInMode(A3) ; Initialize the Video-in Mode to say 8bpp
Move.w D2,saveMonID(A3) ; Save the monID for later.
Move.b dCtlSlotId(A1),saveSlotId(A3) ; Also save the spID.
dRead_Civic #VRAMSize,D2 ; Read the vRAM size register.
Move.b D2,saveSizeVRAM(A3) ; Save it for later.
dRead_Civic #VDCClk,D2 ; Get the state of the VDC clock
Move.w D2,VDCCLkState(A3) ; and save it
dRead_Civic #VDCEnb,D2 ; Get the state of the VDC enable bit
Move.w D2,VDCEnbState(A3) ; and save it
Endwith
;
; Set GFlags to reflect monochrome-only displays.
;
Cmp.w #indexedSenseFP,saveMonID(A3) ; If this is a Mono-Only Full Page,
Beq.s @SetMonoFlags ; then say so.
Cmp.w #indexedSense2P,saveMonID(A3) ; If this is a Mono-Only Two-Page,
Beq.s @SetMonoFlags ; then say so.
Bra.s @AllDone ; Otherwise, skip.
@SetMonoFlags Bset #IsMono,GFlags(A3) ; Turn on the IsMono and
Bset #GrayFlag,GFlags(A3) ; GrayFlag flags.
@AllDone Move.l (SP)+,A4 ; restore our scratch register
MOVEQ #noErr,D0 ; no error
@EndOpen RTS ; return
@OpError5 Adda #sizeSPRamRec,Sp ; Release the SPRam block.
@OpError4 Move.l saveGamDispPtr(A3),A0 ; Set up to dispose of gamma table.
_DisposPtr ; Dispose it.
@OpError3 ADDA #spBlockSize,SP ; release the spBlock
@OpError2 MOVE.L dCtlStorage(A1),A0 ; get the private storage back
_DisposHandle ; release the driver private storage
@OpError1 MOVE.L #OpenErr,D0 ; say can't open driver
Move.l (SP)+,A4 ; restore our scratch register
BRA.S @EndOpen
ENDWITH
**********************************************************************
*
* Video Driver Control Call Handler. There are 15 standard calls:
*
* ($00) Reset (VAR csMode, csPage: INTEGER; VAR csBaseAddr: Ptr);
* ($01) KillIO
* ($02) SetMode(csMode, csPage: INTEGER; VAR BaseAddr: Ptr);
* ($03) SetEntries (csTable: Ptr; Start,Count : integer );
* ($04) SetGamma (csGTable : Ptr );
* ($05) GrayPage (csPage);
* ($06) SetGray (csMode = 0 for color, 1 for gray)
* ($07) SetInterrupt (csMode = 0 for enable, non-zero for disable);
* ($08) DirectSetEntries (Table: Ptr; Start,Count : integer );
* ($09) SetDefaultMode (csMode = mode to set);
* ($0A) SwitchMode (csPageInfo); <LW14>
* ($09) SetSync (csMode = 0 for enable, non-zero for disable); <LW14>
*
* The following calls are Civic-specific:
*
* ($83) SetAltSense(csMode = byte 0 is sense code, byte 1 is type);
* ($85) CivicSetCompOut (csMode = 0 for enable, non-zero for disable); <LW14>
* ($87) SetRGBByPass(csMode = 0 for enable, non-zero for disable); <LW14>
* ($89) SetVidInMode (csMode,csPage: INTEGER; VAR csBaseAddr: Ptr); <LW14>
* ($8A) SetVidInRect (csRect: RECT; csPage: INTEGER; VAR csBaseAddr: Ptr);<LW14>
*
* Entry: A0 = param block pointer
* A1 = AuxDCE pointer
* Uses: A2 = cs parameters (ie. A2 <- csParam(A0)) (must be preserved)
* A3 = ptr to our privates/scrarch (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É
;
CivicVidCtl
MOVEM.L A0/A1,-(SP) ; Save exit registers.
MOVE.L csParam(A0),A2 ; A2 <- Ptr to control parameters
MOVE.L dCtlStorage(A1),A3 ; A3 <- Ptr to private storage
MOVE.L (A3),A3 ;
MOVE.W csCode(A0),D0 ; get routine selector
Cmp.w #$80,D0 ; Is it a private control call
Bhs.s PrivateCtrlCall ; Go decode it
CMP.W #$0B,D0 ; IF csCode NOT IN [0..$B] THEN
BHI.S CivicCtlBad ; Error, csCode out of bounds.
MOVE.W CivicCtlJumpTbl(PC,D0.W*2),D0 ; Get the relative offset to the routine.
JMP CivicCtlJumpTbl(PC,D0.W) ; GOTO the proper routine.
CivicCtlJumpTbl
DC.W CivicVidReset-CivicCtlJumpTbl ; $00 => VidReset
DC.W CivicCtlGood-CivicCtlJumpTbl ; $01 => CtlGood (no async routines here)
DC.W CivicSetVidMode-CivicCtlJumpTbl ; $02 => SetVidMode
DC.W CivicSetEntries-CivicCtlJumpTbl ; $03 => SetEntries
DC.W CivicSetGamma-CivicCtlJumpTbl ; $04 => SetGamma
DC.W CivicGrayPage-CivicCtlJumpTbl ; $05 => GrayPage
DC.W CivicSetGray-CivicCtlJumpTbl ; $06 => SetGray
DC.W CivicSetInterrupt-CivicCtlJumpTbl ; $07 => SetInterrupt
DC.W CivicDirectSetEntries-CivicCtlJumpTbl ; $08 => DirectSetEntries
DC.W CivicSetDefaultMode-CivicCtlJumpTbl ; $09 => SetDefaultMode
DC.W CivicSwitchMode-CivicCtlJumpTbl ; $0A => SwitchMode
DC.W CivicSetSync-CivicCtlJumpTbl ; $0B => SetSync <LW14>
PrivateCtrlCall
CMP.W #$8B,D0 ; IF csCode NOT IN [$80..$8B] THEN
BHI.S CivicCtlBad ; Error, csCode out of bounds.
Subi.w #$80,D0 ; Normalize the code
MOVE.W PrivCtlJumpTbl(PC,D0.W*2),D0 ; Get the relative offset to the routine.
JMP PrivCtlJumpTbl(PC,D0.W) ; GOTO the proper routine.
PrivCtlJumpTbl
DC.W CivicCtlBad-PrivCtlJumpTbl ; $80 => Unused
DC.W CivicCtlBad-PrivCtlJumpTbl ; $81 => Unused
DC.W CivicCtlBad-PrivCtlJumpTbl ; $82 => Unused
DC.W CivicSetAltSense-PrivCtlJumpTbl ; $83 => CivicSetAltSense
DC.W CivicCtlBad-PrivCtlJumpTbl ; $84 => Unused (cscLowPower)
DC.W CivicSetCompOut-PrivCtlJumpTbl ; $85 => CivicSetCompOut
DC.W CivicCtlBad-PrivCtlJumpTbl ; $86 => Unused
DC.W CivicSetRGBByPass-PrivCtlJumpTbl ; $87 => CivicSetRGBByPass
DC.W CivicCtlBad-PrivCtlJumpTbl ; $88 => Unused
DC.W CivicSetVidInMode-PrivCtlJumpTbl ; $89 => SetVidInMode
DC.W CivicSetVidInRect-PrivCtlJumpTbl ; $8A => SetVidInRect
DC.W CivicCtlBad-PrivCtlJumpTbl ; $8B => Unused
CivicCtlBad MOVEQ #controlErr,D0 ; else say we don't do this one
BRA.S CivicCtlDone ; and return
CivicCtlGood MOVEQ #noErr,D0 ; return no error
CivicCtlDone MOVEM.L (SP)+,A0/A1 ; Restore Exit registers.
BRA CivicExitDrvr
CivicVidReset
;---------------------------------------------------------------------
;
; Reset the built-in video to its default
;
;---------------------------------------------------------------------
WITH CivicVidPrivates
MOVE #FirstVidMode,csMode(A2) ; return default mode
Move.w saveMode(A3),d0 ; Get our current mode <LW17> #1083318
Cmp.w saveNewBaseMode(A3),d0 ; If our current mode is ³ the threshold mode where the base address changes <LW17> #1083318
blo.s @NoOffset ; don't need to subract when it's less than <LW17> #1083318
Move.l saveBaseAddr(a3),d0 ; Get our current base <LW17> #1083318
Sub.l saveBaseAddrOffset(a3),d0 ; subtract the offset <LW17> #1083318
Move.l d0,saveBaseAddr(a3) ; and save it <LW17> #1083318
@NoOffset ; <LW17> #1083318
MOVE #FirstVidMode,saveMode(A3) ; remember FirstVidMode as the requested mode
MOVEQ #0,D1 ; get default depth in D1 (#firstVidMode-#firstVidMode)
MOVEQ #0,D0 ; get page in D0
MOVE D0,csPage(A2) ; return the page
BSR CivicSetDepth ; set the depth from D1
BCLR #IsDirect,GFlags(A3) ; turn off direct mode bit
Move.l saveBaseAddr(A3),csBaseAddr(A2) ; return the base address
BSR CivicGrayScreen ; paint the screen gray
BRA.S CivicCtlGood ; => no error
ENDWITH
CivicSetVidMode
;---------------------------------------------------------------------
;
; Set built-in video to the specified mode. Only page zero is possible,
; so we need to check that the request was OK.
;
; Check to see if we are in one of two situations:
;
; 1. We are in a mode where video-in is enabled but the desired mode
; is only suppported without video-in. (Here, go and disable
; video-in before continuing on.
;
; 2. We are in a mode where video-in is not supported and the desired
; mode IS supported with video-in. In this case, go enable video-in
; before continuing on.
;
; If built-in video is already set to the specified mode, then do nothing.
;
;---------------------------------------------------------------------
WITH CivicVidPrivates
MOVE.W csMode(A2),D1 ; D1 = mode
BSR CivicChkMode ; check mode and convert
BNE.S CivicCtlBad ; => not a valid mode
TST.W csPage(A2) ; only page zero is valid
BNE.S CivicCtlBad ; => not a valid page
; Only set if mode has changed.
CivicSetVidModeGuts
MOVE.W csMode(A2),D2 ; get the mode spID (D1 has the zero-based mode)
Move.w saveMode(A3),scratch(A3) ; save our old mode in case we need to know what it was later on
CMP saveMode(A3),D2 ; has the mode changed?
BEQ @JustReturn ; if not, then skip graying
Bsr CivicSetVidModeGuts2
@JustReturn
Move.l saveBaseAddr(A3),csBaseAddr(A2) ; return the base addr
BRA CivicCtlGood ; return no error
; Remember the newly requested mode.
;---------------------------------------------------------------------
;
; This used to be linear code, but I made it a subroutine so that it can
; be called by SetRGBBypass, which does not return a csBaseAddr.
;
;---------------------------------------------------------------------
CivicSetVidModeGuts2
MOVE.W D2,saveMode(A3) ; remember requested mode
Move.l dCtlDevBase(A1),saveBaseAddr(A3) ; Get the base address
Cmp.w saveNewBaseMode(a3),d2 ; If our desired mode is
blo.s @NoOffset ; less than the offset-threshold mode, don't update the base address
Move.l saveBaseAddrOffset(A3),d0 ; get our new offset
add.l d0,saveBaseAddr(A3) ; and save our new base address
@NoOffset
; Set the entire color table to gray before switching to avoid screen anomalies.
Movem.l A4-A6/D4-D5,-(Sp) ; Save gamma-table registers.
Move.l saveGammaPtr(A3),A0 ; Get pointer to gamma data structure.
Lea gFormulaData(A0),A4 ; Point to first gamma table.
Adda.w gFormulaSize(A0),A4 ;
Move.l A4,A5 ; Point to green data (assuming gChanCnt = 1).
Move.l A4,A6 ; Point to red data (assuming gChanCnt = 1).
Cmp.w #1,gChanCnt(A0) ; If thereÕs only one table,
Beq.s @OnlyOneTable ; then weÕre set.
Move.w gDataWidth(A0),D2 ; Get width of each entry (in bits).
Move.w gDataCnt(A0),D0 ; Get # of entries in table.
Addq #7,D2 ; Round to nearest byte.
Lsr.w #3,D2 ; Get bytes per entry.
Mulu D2,D0 ; Get size of table in bytes.
Adda.w D0,A5 ; Calc base of green (red base + D0).
Adda.w D0,A6 ; Calc baseÉ
Adda.w D0,A6 ; Éof blue (red base + D0 + D0).
@OnlyOneTable
Move.w gDataCnt(A0),D3 ; Save number of gamma entries.
MOVE.L saveVDACBase(A3),A0 ; get the VDAC base addr
Move.b SebastPCBR(A0),D0 ; Make sure we're writing to the Graphics CLUT
Bclr #fCivicVidInCLUT,D0 ; by zeroing the CLUT select bit in the PCBR
Move.b D0, SebastPCBR(A0) ; and write it back out.
ADDA.W #SebastDataReg,A0 ; point to data register
Moveq #0,D4 ; D4 contains the beginning of the CLUT
Move.b D4,SebastAddrReg-SebastDataReg(A0) ; start at the beginning of CLUT
MOVE.W SR,-(SP) ; preserve the status register
BSR CivicWaitVSync ; wait for next blanking period (preserves A0)
; Write out gamma-corrected true-gray CLUTÉ
;
Move.w D3,D0 ; Init loop counter.
Subq #1,D0 ; Zero base it.
Move.w GFlags(A3),D2 ; Get the GFlags into a convenient register.
Lsr.w #1,D3 ; Get midpoint of table(s).
Btst #videoInEnb,D2 ; If video-in is enabled, need to read the alpha
Bne @VidInRepeat ; before writing the grey
@Repeat Btst #IsMono,D2 ; If this is not a mono-only display
Beq.s @DoRGB ; then do the standard RGB stuff.
Clr.b (A0) ; Otherwise, just write black out
Clr.b (A0) ; to the red & green channels.
Bra.s @DoMono ;
@DoRGB Move.b (A4,D3),(A0) ; Write: red,
Move.b (A5,D3),(A0) ; green,
@DoMono Move.b (A6,D3),(A0) ; blue,
Clr.b (A0) ; alpha.
Dbra D0,@Repeat
Bra.s @FinishedGray ; Go set depth
@VidInRepeat Move.b (A0),D5 ; Read: red,
Move.b (A0),D5 ; green,
Move.b (A0),D5 ; blue,
Move.b (A0),D5 ; alpha,
Move.b D4,SebastAddrReg-SebastDataReg(A0) ; Reset the CLUT Address register
Btst #IsMono,D2 ; If this is not a mono-only display
Beq.s @VidInDoRGB ; then do the standard RGB stuff.
Clr.b (A0) ; Otherwise, just write black out
Clr.b (A0) ; to the red & green channels.
Bra.s @VidInDoMono ;
@VidInDoRGB Move.b (A4,D3),(A0) ; Write: red,
Move.b (A5,D3),(A0) ; green,
@VidInDoMono Move.b (A6,D3),(A0) ; blue,
Move.b D5,(A0) ; alpha.
Addq #1,D4 ; Increment the CLUT Address Register
Dbra D0,@VidInRepeat
@FinishedGray
MOVE (SP)+,SR ; restore the status reg
Movem.l (Sp)+,A4-A6/D4-D5 ; Restore gamma-table registers.
BSR CivicSetDepth ; set the depth from D1
; Finish up the bookkeeping.
CMP.W #FifthVidMode,saveMode(A3) ; was it a direct mode?
BLT.S BitOff ; no, so turn flag off
BSET #IsDirect,GFlags(A3) ; turn on bit
BRA.S ModeOK1 ;
BitOff
BCLR #IsDirect,GFlags(A3) ; turn off bit
ModeOK1
Rts
ENDWITH
CivicSetEntries
;---------------------------------------------------------------------
;
; Input :
; csParam -> datablock
; datablock = csTable -> table of colorSpecs (not colortable)
; csStart -> where to start setting, or -1, or -2
; 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 AuxDCE
; 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 CivicVidPrivates,CivicCLUTRec
BTST #IsDirect,GFlags(A3) ; are we in a direct mode?
BNE.S CivicCtlBad ; error if so
CivicSEGuts
TST.L csTable(A2) ; Check for a nil pointer
BEQ CivicCtlBad ;
MOVEM.L A1/A4-A6/D4-D7,-(SP) ; save registers for gamma
MOVE.W GFlags(A3),D5 ; get GFlags word in D5
Cmp.w #alphaEntries,csStart(A2) ; Do we have alpha entries (XColorSpec)
Bne.s @SkipAlpha ; if not, leave bit off
Bset #HasAlpha,D5 ; turn on the bit that denotes that the csTable has alpha entries. This will always use an
Bra.s @SkipSeq ; indexed mode to write to the CLUT, so skip the Sequential stuff.
@SkipAlpha
CMP.W #indexEntries,csStart(A2) ; was it indexed mode?
BEQ.S @SkipSeq ; if so, then leave bit off (it's never turned on in GFlags)
Bset #PsuedoIndex,D5 ; turn on the bit that denotes a seq write that was xlated to indexed
Cmp.w #FourthVidMode,saveMode(A3) ; If itÕs not 8bbp, 16bpp, or 32bpp,
Blt.s @SkipSeq ; need to use ÒindexedÓ.
BSET #UseSeq,D5 ; otherwise, turn on sequential mode bit
@SkipSeq
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,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
ADDQ #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
ADDA D0,A6 ; calc base of blue
ADDA D0,A6 ; calc base of blue
@OneTbl
;
; Get the maximum number of entries, zero based from a convenient table.
;
MOVE.W saveMode(A3),D1 ; get the current video mode
SUB.W #FirstVidMode,D1 ; convert to a index
Moveq #0,D6 ; clear all of D6 for .w compare.
Lea CivicCLUTTbl,A0 ; Point to the table of CLUT data.
Lea (A0,D1*CivicCLUTSize),A0 ; Point to the right entry.
Move.b ccRange(A0),D6 ; Get the range.
;
; Allocate a temporary color table on the stack. We'll pre-process all the entries that will
; change here so we can hit the hardware as quickly as possible.
;
MOVE.W csCount(A2),D3 ; get the number of entries to change
CMP.W D6,D3 ; is it in the allowable range
BHI CivicSEBadExit ; if out of range, then exit w/bad result
Move.w csStart(A2),D0 ; Get the start number to range check.
Addq.w #2,D0 ; If csStart < -2, then itÕs out of
Bmi CivicSEBadExit ; range.
Move.w csStart(A2),D0 ; Get the start number to range check.
Bmi @SkipUpperRangeCheck ; Only do it if csStart is positive or 0.
Add.w csCount(A2),D0 ; If csStart + ccCount exceeds the allowable range
Cmp.w D6,D0 ; D6 has the max range for the CLUT
BHI CivicSEBadExit ; if out of range, then exit w/bad result
@SkipUpperRangeCheck
Move.l D3,D4 ; Make a copy of the table size (zero-based).
Addq #1,D4 ; Make it a counting number.
Btst #UseSeq,D5 ; If weÕre not in sequential mode,
Beq.s @IsIndex ; then do the indexed stuff.
Asl.w #2,D4 ; Make room for just R,G,B,alpha in sequential mode.
Bra.s @AllocIt ; And continue.
@IsIndex Mulu #5,D4 ; Make room for i,R,G,B,alpha in indexed mode.
@AllocIt Sub.w D4,Sp ; Allocate the table on the stack.
;
; Construct the stack version of the color table. It looks like a color table, but each of the
; components is only eight bits (rather than 16).
;
Move.l A3,D6 ; WeÕre about to torch A3, so save it for later.
Move.l A0,A3 ; Save the CLUT table entry pointer.
MOVE.L SP,A0 ; copy the stack buffer pointer
MOVE.L csTable(A2),A1 ; get colorSpec pointer into 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 or -2 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 (8/16) 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 ; If we are doing an ÒindexedÓ mode,
Beq.s @IndexPresent ; then go there now.
; This case is a sequential request in a screen depth that does not allow sequential CLUT writes
; (any non-8/16/32 bit mode). In this case, we substitute the sequence counter for D0 on each
; entry.
Move.w D4,D0 ; Copy the sequence counter to D0.
Addq #1,D4 ; Increment it.
@IndexPresent Mulu.w ccSkip(A3),D0 ; Calculate the new position at this depth.
Add.b ccStart(A3),D0 ; Add in the first entry offset.
Move.b D0,(A0)+ ; Write out this index.
@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 luminance 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},D0 ; get gChanWidth bits for gamma table lookup
MOVE.W D0,D1 ; copy into green register
MOVE.W D0,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
BTST #IsMono,D5 ; if monochrome display, write black to red & green
BEQ.S @Brighter ; if not, then set all three channels
CLR.B (A0)+ ; write black for red
CLR.B (A0)+ ; and green
BRA.S @Looper ; write out normal blue
@Brighter
MOVE.B (A4,D0),(A0)+ ; write gamma corrected red
MOVE.B (A5,D1),(A0)+ ; write gamma corrected green
@Looper
MOVE.B (A6,D2),(A0)+ ; write gamma corrected blue
Btst #HasAlpha,D5 ; test to see if color table has an alpha entry
Beq.s @NoAlpha ; it doesn't, write a zero for that entry
Move.w (A1)+,D0 ; get the 16-bit alpha value
Move.b D0,(A0)+ ; and write it to the table as 8 bits
Bra.s @DoTheLoop ; go loop
@NoAlpha
Clr.b (A0)+ ; Write zero for the alpha entry
@DoTheLoop
DBRA D3,@SetupLoop ; and loop for each entry
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 Sr,-(Sp) ; Preserve the status register. (Watch out for LEA 2(SP) )
Move.l D6,A3 ; Get our privates pointer back into A3 (for WaitVSync).
BSR CivicWaitVSync ; Wait for next blanking period (preserves A0/D0).
MOVE.W csCount(A2),D3 ; get the count again
MOVE.L saveVDACBase(A3),A3 ; get the VDAC base
Move.b SebastPCBR(A3),D0 ; Make sure we're writing to the Graphics CLUT
Bclr #fCivicVidInCLUT,D0 ; by zeroing the CLUT select bit in the PCBR
Move.b D0, SebastPCBR(A3) ; and write it back out.
LEA SebastDataReg(A3),A3 ; point to VDAC data register
LEA 2(SP),A0 ; point to the stack buffer again
;
; Check to see if video-in is enabled
;
Btst #videoInEnb,D5 ; is video-in enabled
Bne.s CivicVinIndexWrite ; if it is, then go check whether is indexed/sequenced
BTST #UseSeq,D5 ; is it sequence mode?
BNE.S CivicSeqWrite ; yup, sequence mode, so go there
;
; Here's the loop that actually writes to the hardware when in indexed mode.
;
CivicIndexWrite
MOVE.B (A0)+,SebastAddrReg-SebastDataReg(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
MOVE.B (A0)+,(A3) ; write alpha
DBRA D3,CivicIndexWrite ; and loop
BRA.S CivicSEDone ;
;
; Write out the translated starting position for sequence mode.
;
CivicSeqWrite
MOVE.W csStart(A2),D0 ; get sequence start address
MOVE.B D0,SebastAddrReg-SebastDataReg(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) ; write red
MOVE.B (A0)+,(A3) ; write green
MOVE.B (A0)+,(A3) ; write blue
MOVE.B (A0)+,(A3) ; write alpha
DBRA D3,@SeqLoop ; and loop
BRA.S CivicSEDone ;
;
; Video in is enabled here. Need to check if we actually have alpha data in the table we built.
; If so, go back to the CivicIndexWrite (it's always in indexed mode when we have alpha). Also,
; check if there is no real alpha in the table, whether it's a sequence write (Table has: r,g,b,alpha)
; or an index write (Table has index,r,g,b,alpha).
;
CivicVinIndexWrite
Btst #HasAlpha,D5 ; Do we have alpha data?
Bne CivicIndexWrite ;If so, do a regular index write that uses the stack data
BTST #UseSeq,D5 ; is it sequence mode?
BNE.S CivicVinSeqWrite ; yup, sequence mode, so go there
;
; Here's the loop that actually writes to the hardware when in indexed mode and video-in enabled.
; We first read the RGB+alpha for the index value from the CLUT, and use this last alpha when we
; write it back in.
;
CivicVinIndexWriteLoop
Move.b (A0),SebastAddrReg-SebastDataReg(A3) ; write the index value to the CLUT address
Move.b (A3),D7 ; read the red
Move.b (A3),D7 ; read the green
Move.b (A3),D7 ; read the blue
Move.b (A3),D7 ; read the alpha
MOVE.B (A0)+,SebastAddrReg-SebastDataReg(A3) ; re-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
Move.b D7,(A3) ; write alpha
Tst.b (A0)+ ; skip past the alpha in the table we built
DBRA D3,CivicVinIndexWriteLoop ; and loop
BRA.S CivicSEDone ;
;
; Write out the translated starting position for sequence mode with video-in enabled.
;
CivicVinSeqWrite
MOVE.W csStart(A2),D0 ; get sequence start address
MOVE.B D0,SebastAddrReg-SebastDataReg(A3) ; write the sequence start position
;
; Here's the loop that actually writes to the hardware when in sequence mode. Again, first
; we read the values in the CLUT, save the alpha (discarding RGB) and write the new values
; with the old alpha. The address register is self-incrementing, so we make use of this
; feature to only write it once. When we're reading the values, the addess register already
; has the "next" address
;
@SeqVinLoop
Move.b (A3),D7 ; read the red
Move.b (A3),D7 ; read the green
Move.b (A3),D7 ; read the blue
Move.b (A3),D7 ; read the alpha
Move.b D0,SebastAddrReg-SebastDataReg(A3) ; write the sequence start position
MOVE.B (A0)+,(A3) ; write red
MOVE.B (A0)+,(A3) ; write green
MOVE.B (A0)+,(A3) ; write blue
Move.b D7,(A3) ; write alpha
Tst.b (A0)+ ; skip past the alpha in the table we built
Addq #1,D0 ; increment the sequence start address
DBRA D3,@SeqVinLoop ; and loop
;
; Clean up and go home.
;
CivicSEDone
MOVE (SP)+,SR ; restore status register
ADD D4,SP ; release stack buffer
MOVEM.L (SP)+,A1/A4-A6/D4-D7 ; restore registers
BRA CivicCtlGood ; return O-Tay!
CivicSEBadExit
MOVEM.L (SP)+,A1/A4-A6/D4-D7 ; restore registers
BRA CivicCtlBad ; return an error code
ENDWITH
CivicSetGamma
;---------------------------------------------------------------------
;
; 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 AuxDCE
; A2 = Ptr to cs parameter record
;
;---------------------------------------------------------------------
WITH CivicVidPrivates
; Get new gamma table and check that we know how to handle it.
MOVE.L csGTable(A2),D0 ; test for a NIL pointer
BEQ @LinearTab ; if so, then set up a linear gamma table
MOVE.L D0,A2 ; get pointer to new gamma table
TST.W gVersion(A2) ; version = 0?
BNE CivicCtlBad ; => no, return error
Tst.w gType(A2) ; Test the hardwareID.
Beq.s @ChangeTable ; If 0, then accept a TFB-style gamma table.
CMP.W #drHwCivic,gType(A2) ; type = Civic?
BNE CivicCtlBad ; => no, return error
TST.W gFormulaSize(A2) ; if gType=Civic, then check for monID in gFormulaData
BEQ.S @ChangeTable ; if zero, then generic, so continue
MOVE.W gFormulaData(A2),D0 ; get the monitor ID this table was intended for
CMP.W saveMonID(A3),D0 ; is this the monitor?
BEQ.S @ChangeTable ; yes, so do it
ADDQ #1,D0 ; was it -1?
BNE CivicCtlBad ; nope, so must be wrong monitor
; If new table is a different size, reallocate memory.
@ChangeTable
MOVE.L saveGammaPtr(A3),A0 ; get current gamma in A0
MOVE gFormulaSize(A2),D0 ; get size of formula in new
CMP gFormulaSize(A0),D0 ; same as current gamma table
BNE.S @GetNew ; =>no, resize pointer
MOVE gChanCnt(A2),D0 ; get number of tables in new
CMP gChanCnt(A0),D0 ; same as current gamma table?
BEQ.S @SizeOK ; => yes, data size ok
BGT.S @GetNew ; => new one is bigger, save old one
@NewSize Move.l saveGamDispPtr(A3),A0 ; if new one is smaller,
_DisposPtr ; dispose old one
CLR.L saveGamDispPtr(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 CivicCtlBad ; => unable to allocate storage
MOVE.L saveGamDispPtr(A3),D0 ; get old gamma table
MOVE.L A0,saveGammaPtr(A3) ; save new gamma table
TST.L D0 ; was there an old one?
BEQ.S @SizeOK ; => no, already disposed
MOVE.L D0,A0 ; else get old table
_DisposPtr ; and dispose of old gamma table
MOVE.L saveGammaPtr(A3),A0 ; get new gamma table back
Move.l A0,saveGamDispPtr(A3) ; save it for disposal
; Copy the gamma table header.
@SizeOK MOVE gChanCnt(A2),D0 ; get number of tables
MOVE gFormulaSize(A2),D1 ; get size of formula data
MOVE gDataCnt(A2),D2 ; get number of entries
MOVE.L (A2)+,(A0)+ ; copy gamma header
MOVE.L (A2)+,(A0)+ ; which isÉ
MOVE.L (A2)+,(A0)+ ; É12 bytes long
; Copy the data.
MULU D0,D2 ; multiply by number of tables
ADD D1,D2 ; add in size of formula data
SUBQ #1,D2 ; get count - 1
@NxtByte MOVE.B (A2)+,D0 ; get a byte
MOVE.B D0,(A0)+ ; move a byte
DBRA D2,@NxtByte ; => repeat for all bytes
Bra.s @GammaDone ; Check to see if itÕs a direct device.
;
; Set up a linear gamma table. To prevent memory thrash, build this new one
; the same size as the existing one (one or three channel).
;
@LinearTab
MOVE.L saveGammaPtr(A3),A0 ; get current gamma in A0
MOVE.W gFormulaSize(A0),D0 ; get size of formula in new
MOVE.W gChanCnt(A0),D2 ; get the number of tables
SUBQ #1,D2 ; zero based, of course
Move.w gDataCnt(A0),D3 ; get the number of entries
Subq #1,D3 ; zero base
ADDA #gFormulaData,A0 ; point to tables
ADDA D0,A0 ; point past monID, if present
@ChanLoop MOVE.W D3,D0 ; loop count within each channel
@entryLoop MOVE.B D0,(A0) ; write this value out
Not.b (A0)+ ; invert to make table ramp properly
DBRA D0,@entryLoop ; for each entry in channel
DBRA D2,@ChanLoop ; and each channel
@GammaDone
BTST #IsDirect,GFlags(A3) ; are we in a direct mode?
BEQ.S @Out ; if not, then we're done
BSR CivicDirectCLUTSet ; if so, then set up direct CLUT ramps
@Out
BSR CivicVideoCLUTSet ; Set up the VideoCLUT ramps
BRA CivicCtlGood ; => return no error
ENDWITH
CivicGrayPage
;---------------------------------------------------------------------
;
; Clear the specified page in the current mode to gray
;
; A0 = Ptr to private storage
; A1 = Ptr to AuxDCE
; A2 = Ptr to cs parameter record
; A3 = Ptr to driver privates
;
;---------------------------------------------------------------------
WITH CivicVidPrivates
Move.l A5,-(SP) ; Save our work register
MOVE saveMode(A3),D1 ; D1 = mode
BSR CivicChkMode ; convert mode to depth in D1
BNE CivicCtlBad ; => not a valid depth
MOVE csPage(A2),D0 ; D0 = page
BNE CivicCtlBad ; => not a valid page
; Disable Overlay if video-in is on and the overlay bit is set
Btst #videoInEnb,GFlags(A3) ; Is it on
Beq.s @GrayIt ; if not, don't do anything
Move.l saveVDACBase(A3), A5 ; Get the a pointer to CLUT/DAC
Move.b SebastPCBR(A5), D0 ; Get the PCBR Value
Btst #fCivicVidInOvly,D0 ; Is it ON
Sne scratch(A3) ; if it is, save a flag
Bclr #fCivicVidInOvly,D0 ; Disable Overlay
Move.b D0,SebastPCBR(A5) ; Write it out
@GrayIt
BSR CivicGrayScreen ; paint the screen gray
BTST #IsDirect,GFlags(A3) ; are we in a direct mode?
BEQ.S @Out ; if not, then we're done
BSR CivicDirectCLUTSet ; if so, then set up direct CLUT ramps
@Out
BSR CivicVideoCLUTSet ; Set up the VideoCLUT ramps
Btst #videoInEnb,GFlags(A3) ; Is it on
Beq.s @Exit ; if not, don't do anything
Tst.b scratch(A3) ; Was the overlay bit set?
Beq.s @Exit ; no, so don't retouch it.
Move.b SebastPCBR(A5), D0 ; Get the PCBR Value
Bset #fCivicVidInOvly,D0 ; Enable Overlay
Move.b D0,SebastPCBR(A5) ; Write it out
@Exit
Move.l (Sp)+,A5 ; Restore our work register
BRA CivicCtlGood ; => return no error
ENDWITH
CivicSetGray
;---------------------------------------------------------------------
;
; 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 AuxDCE
; A2 = Ptr to cs parameter record
; A3 = Ptr to private storage
;
;---------------------------------------------------------------------
WITH CivicVidPrivates
BTST #IsMono,GFlags(A3) ; is this a mono-only monitor?
BEQ.S @1 ; if not, then go ahead
MOVE.B #1,csMode(A2) ; always turn on for mono devices
@1 MOVEQ #0,D1 ; set up for BFEXTU to point to GrayFlag
BSR.S CivicSetIntCom ; call common code
BRA CivicCtlGood ; all done
;
; This shared routine sets up a flag in GFlags. It takes a pointer to
; private storage in A3, and the bit field start location in D1.
;
CivicSetIntCom
MOVE.B csMode(A2),D0 ; get boolean
BFINS D0,GFlags(A3){D1:1} ; set flag bit
RTS ; and return
ENDWITH
CivicSetInterrupt
;---------------------------------------------------------------------
;
; 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 AuxDCE
; A2 = Ptr to cs parameter record
; A3 = Ptr to private storage
;
;---------------------------------------------------------------------
WITH VDPageInfo,SlotIntQElement,CivicVidPrivates,CivicRecord
MOVEQ #1,D1 ; set up for BFEXTU to point to IntDisFlag
BSR.S CivicSetIntCom ; call common code
BNE.S @DisableThem ; if zero, then enable
; This code enables interrupts and installs the interrupt handler.
;
BSR.S CivicEnableVGuts ; call common code
BNE CivicCtlBad ; error, flag problem
BRA CivicCtlGood ; and go home
; This code disables VBL interrupts, then removes the interrupt handler.
;
@DisableThem
BSR.S CivicDisableVGuts ; jump to the disabling utility
BRA CivicCtlGood ; all done
; The following two routines are common code shared between the Open/Close calls
; and the SetInterrupt control call.
;
CivicDisableVGuts
MOVE.W SR,-(SP) ; preserve the status register
BSR CivicWaitVSync ; to be safe, wait for the next VBL
dWrite_Civic #0,#VBLEnb ; Disable Civic VBLs.
dWrite_Civic #0,#VBLClr ; Clear the current VBL.
MOVE (SP)+,SR ; re-enable cursor interrupts
CLR.W D0 ; setup slot 0 for _SIntRemove
MOVE.L saveSQElPtr(A3),A0 ; get the SQ element pointer
_SIntRemove ; remove the interrupt handler
RTS
CivicEnableVGuts
MOVE.L saveSQElPtr(A3),A0 ; get the queue element
LEA CivicBeginIH,A2 ; save Pointer to interrupt handler
MOVE.W #SIQType,SQType(A0) ; setup queue ID
Move.W #255,SQPrio(A0) ; Give the VBL top priority
MOVE.L A2,SQAddr(A0) ; setup int routine address
MOVE.L A3,SQParm(A0) ; pass pointer to privates as the parameter
CLR.W D0 ; setup slot zero
_SIntInstall ; and do install
BNE.S @IntBad
dWrite_Civic #1,#VBLEnb ; Enable Civic VBLs.
dWrite_Civic #1,#VBLClr ; Un-Clear VBLs.
CMP D0,D0 ; clear z-bit for good result
@IntBad RTS ; return home (if bad, z-bit is set above, so just leave) <8>
ENDWITH
CivicDirectSetEntries
;---------------------------------------------------------------------
;
; Change the CLUT in a direct mode.
;
; A1 = Ptr to AuxDCE
; 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.S CivicCtlBad ; error if not
BRA.S CivicSEGuts ; jump to SetEntries internals if it's OK
CivicSetDefaultMode
;---------------------------------------------------------------------
;
; Write the card default mode into slot pRAM.
;
; A1 = Ptr to AuxDCE
; 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,CivicVidPrivates,SP_Params
;
; 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. Built-in video keeps the video
; sRsrc spID in VendorUse2.
;
SUBA #SizesPRAMRec,SP ; allocate block for pRAM record
MOVE.L SP,spResult(A0) ; point to it
_sReadPRAMRec ; read it
;
; Since PrimaryInit relies on the default mode being set correctly, we check to see that
; the mode to be set is actually valid. Monitors can only see valid sRsrcIDs, so
; it probably wonÕt cause a problem. But we should check it anyway for unsavory
; applications.
;
Move.b csMode(A2),spID(A0) ; Look for the passed in spID.
Clr.l spParamData(A0) ; Clear the fNext flag; we want THIS sRsrc.
Ori.b #(1<<fall)|\ ; Search for both enabled/disabled sRsrcÕs
(1<<foneslot),spParamData+3(A0) ; Only search in our slot.
_GetsRsrc ; Do it.
Bne.s @BadExit ; If failed, quit.
Move.w spCategory(A0),D0 ; Get the category.
Cmp.w #catDisplay,D0 ; If itÕs not catDisplay,
Bne.s @BadExit ; then quit.
Move.w spCType(A0),D0 ; Get the type.
Cmp.w #typVideo,D0 ; If itÕs not typVideo,
Bne.s @BadExit ; then quit.
Move.w spDrvrSw(A0),D0 ; Get the software kind.
Cmp.w #drSwApple,D0 ; If itÕs not drSwApple,
Bne.s @BadExit ; then quit.
Move.w spDrvrHw(A0),D0 ; Get the hardware ID.
Cmp.w #drHwCivic,D0 ; If itÕs not drHwCivic,
Bne.s @BadExit ; then quit.
;
; 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),SP_LastConfig(SP) ; write the mode into pRAM buffer
MOVE.L SP,spsPointer(A0) ; set up parameter block
_sPutPRAMRec ; write the new record out
@GoodExit ADDA #SizesPRAMRec+spBlockSize,SP ; Deallocate buffer and
BRA CivicCtlGood ; return good result.
@BadExit Adda #SizesPRAMRec+spBlockSize,SP ; Deallocate buffer and
Bra CivicCtlBad ; return bad result.
ENDWITH
CivicSetVidInMode
;---------------------------------------------------------------------
;
; Set the Video-in parameters in Civic to the values specified in
; the rect passed to the routine.
;
; Entry: A1 = Ptr to AuxDCE
; A2 = Ptr to cs parameter record
; A3 = Ptr to private storage (CivicVidPrivates)
;
; Used: A0 = scratch Ptr to CivicVidInTable
; A4 = scratch Ptr to VidParams (restored)
; A5 = scratch Ptr to SebastBase (restored)
;
;---------------------------------------------------------------------
WITH VDPageInfo, CivicVidPrivates, CivicVidParams, CivicBppParams, CivicRecord
Tst.w csPage(A2) ; only page zero is valid
Bne.s CivicCtlBad ; => not a valid page
MOVEM.L A4-A6/D3-D7,-(SP) ; Save scratch registers
; Bail out if video-in is not enabled.
Btst #videoInEnb,GFlags(A3) ; If Video-in is not enabled
Beq VidInCtlBad ; then return error.
Move.w csMode(A2),D2 ; Get the mode
Cmp.w #8,D2 ; 8
Beq CVidInModeOK ;
Cmp.w #16,D2 ; or 16
Beq CVidInModeOK ;
Bra VidInCtlBad ; return error due to incorrect csMode
CVidInModeOK
Move.l #vCivicVidInBase,csBaseAddr(A2) ; Return the static video-in VRAM base address
;
; Check to see if the Overlay Bit in Sebastian is enabled. If not, assume video-in was not turned on
; and if it is, check to see whether the desired video bpp is different than what's already showing. If
; it isn't, we don't need to change anything!
Move.w saveVidInMode(A3),scratch(a3) ; Save our mode in case we need to bail out <LW17> #1084366
Move.w D2,saveVidInMode(a3) ; Save the mode in our privates.
Lsr.w #4,D2 ; Make csMode zero-based (0 = 8bpp, 1 = 16bpp)
Move.l saveVDACBase(A3), A5 ; Get the a pointer to CLUT/DAC
Move.b SebastPCBR(A5), D7 ; Get the PCBR Value
Move.b D7,D0 ; Get a temporary value for it
Btst #fCivicVidInOvly,D7 ; Check to see if overlay is enabled
Beq.s CVidInMonSupport ; ( 0 = not enabled )
Lsr.b #fCivicVidInBpp,D0 ; Overlay was enabled: Move the video-in bpp bit
Andi.b #1,D0 ; and mask it so that it's $01 or $00
Cmp.b D0,D2 ; If equal to our zero-based csMode, then do nothing
Beq CVidInGoHome ; return good status (returning MMU mode to correct state)
CVidInMonSupport
;
; Check to see if the monitor supports the desired bpp depth. D2 contains this depth. 0 = 8 bpp, 1 = 16bpp
;
Move.l saveVidPtr(A3),A4 ; Get the pointer to our video parameters
Move.b cvpMaxVidInMode(A4),D0 ; Get the maximum video-in mode
Sub.b #FourthVidMode,D0 ; Make the vid-in mode zero-based (0=8bpp, 1=16bpp)
Cmp.b d0,d2 ; If desired mode > max mode,
Bhi CVidInBad ; then we don't support it.
WITH CivicVidInRec, CVidInVRAMRec, CVidInBPPRec
; Turn off overlay while we do this stuff, so we don't get video all over the screen when we change parameters
;
Bclr #fCivicVidInOvly,D7 ; Disable overlay
Move.b D7,SebastPCBR(A5) ; and write it out
Bsr CGetVidInMonTable
Move.w cVidInMaxH(A0),D0 ; Get the Maximum Horizontal value
; Check to see if VidInMaxH == -1; If so, call a subroutine to calculate the maximum height given a width, for the monitor/VRAM configuration pair:
Cmp.w #-1, D0 ; is VidInMaxH == 0
Bne CivicVidInGetWidth ; nope
Move.w currentRight(a3),D1 ; Get the current VidInRect's width
Sub.w currentLeft(a3),D1 ; into D1
Bsr CivicCalcMaxHeight ; Uses D1 as the current width, calculates max height and returns it in D0
Tst.w D0 ; Was the width 0
Beq CVidInGetbpp ; If width == 0, then height == 0 and there was no vidinrect so just carry on.
Move.w currentBottom(a3),D1 ; Get the current VidInRect's height
Sub.w currentTop(a3),D1 ; into D1
Cmp.w D0,D1 ; is the current height > than the max allowed
Bgt CVidInBad ; yup
Bra CVidInGetbpp
; Check to see that the current VidInRect's width is less that the max width allowed, and also that the current height is less than the max width allowed.
; Return an error through CVidInBad to tell say that the specified bpp is illegal.
CivicVidInGetWidth
Move.w currentRight(a3),D1 ; Get the current VidInRect's width
Sub.w currentLeft(a3),D1 ; into D1
Cmp.w D0,D1 ; is the current width > than the max allowed
Bgt CVidInBad ; yup
Move.w cVidInMaxV(A0),D0 ; Get the Maximum Vertical value
Move.w currentBottom(a3),D1 ; Get the current VidInRect's height
Sub.w currentTop(a3),D1 ; into D1
Cmp.w D0,D1 ; is the current height > than the max allowed
Bgt CVidInBad ; yup
Bra CVidInGetbpp
ENDWITH
; Now, do separate stuff for video-in 16bpp and video-in 8bpp
;
CVidInGetbpp
Lsl.w #fCivicVidInBpp,D2 ; Get the zero-based vid-in mode and shift it to the correct position
Andi.b #$F7,D7 ; Clear the video-in bpp
Or.b D2,D7 ; and set/clear it depending on the vid-in mode
Jsr CSetVidInModeGuts
Move.l saveVDACBase(A3),A5 ; Get a pointer to the CLUT Base
Bset #fCivicVidInOvly,D7 ; Set the overlay enable
Move.b D7,SebastPCBR(A5) ; and write it out
; Now resize the vid in rect
Move.l saveVidPtr(A3),A4 ; Get a pointer to the video params.
Move.w currentRight(a3),-(SP) ; Get the current video in rect
Move.w currentBottom(a3),-(SP) ;
Move.w currentLeft(a3),-(SP) ;
Move.w currentTop(a3),-(SP) ; in reverse order
Jsr CivicSetVidRectJSR ; Go do the work
Adda #8,SP ; Clean up the stack
BSR CivicVideoCLUTSet ; Set up the VideoCLUT ramps
Bra CVidInGoHome
CGetVidInMonTable
; This subroutine will return A0 pointing to the correct Rect entry in CivicVidInTable, depending
; on the video-in bpp depth and the amount of VRAM. It is used by SetVidInMode to determine if the
; desired mode is supported by the monitor, and by SetVidInRect to determine what the maximum rect
; size is available in the current monitor/vid-in bpp combination.
;
; Needs: A3: Points to CivicVidPrivates
; A4: Points to VidParams
; D2: Zero-based video-in bpp depth: 0 = 8bpp, 1 = 16bpp
;
; Trashes: A0/D0/D1
;
; Returns: A0: Points to the correct video-in monitor entry.
;
; Check to see if the monitor supports the desired bpp depth. D2 contains this depth. 0 = 8 bpp, 1 = 16bpp
;
WITH CivicVidInRec, CVidInVRAMRec, CVidInBPPRec
;
; Check to see if we're driving out of the composite out and adjust the "monitor sensed"
; accordingly
Move.w GFlags(A3),D1 ; Get our flags
Btst #CompositeSyncOn,D1 ; Are we driving comp sync
Beq.s @ChkMultisync ; nope, so use the saveMonID <LW14>
Btst #NTSCTimingOn,D1 ; Are we driving NTSC?
beq.s @DrivingPAL ; no, we are doing PAL
Move.w #indexedSenseNTSC,D1 ; yes, say we have NTSC
Bra.s @ModifiedID
@DrivingPAL
Move.w #indexedSensePAL,D1 ; say we are driving PAL
bra.s @ModifiedID ; don't adjust D1 <LW14>
@ChkMultisync ; <LW14>
Cmpi.w #indexedSenseMSB1,saveMonID(A3) ; If weÕre not in the multiscan mode, <LW14>
bne.s @OutRGBSyncs ; don't adjust D1 <LW14>
Move.w D2,-(SP) ; Save D2 'cause we trash it <LW14>
Move.b dCtlSlotID(A1),D2 ; Get the SpID. <LW14>
Moveq #0,D0 ; Clear hi-half of mode/depth register. <LW14>
Lea EquivalendMonIDTable,A0 ; get the equivalent ID table <LW14>
@ChkLoop Move.b (A0)+,D1 ; If weÕre at the end of the table, <LW14>
Beq @BadExit ; then somethingÕs wrong. <LW14>
Move.b (A0)+,D0 ; Get the monID for this config. <LW14>
Cmp.b D1,D2 ; If this is not our spID, <LW14>
Bne.s @ChkLoop ; then keep looping. <LW14>
Move.w D0,D1 ; else, get our monID into the desired register <LW14>
Move.w (Sp)+,D2 ; Restore D2 <LW14>
Bra.s @ModifiedID ; and calculate the max size <LW14>
@OutRGBSyncs ; <LW14>
Move.w saveMonID(A3),D1 ; Get the monitor ID entry <LW14>
@ModifiedID
Lea CivicVidInTable,A0 ; Point to the Civic Video-In Table <LW14>
Move.w #CivicVidInRecSize,D0 ; Get the size of each entry into D0 <LW14>
Mulu D1,D0 ; Multiply it by the right entry
Adda.l D0,A0 ; Skip to the right monitor entry
Move.b saveSizeVRAM(A3),D1 ; VRAM size: 0 = 1Meg, 1 = 2Meg
Move.w #CVidInVRAMRecSize,D0 ; Get the size of each VRAM parameters entry
Mulu D1,D0 ; Multiply it by the right value
Adda.l D0,A0 ; and now point to the right VRAM entry
Move.w #CVidInBPPRecSize,D0 ; Get the size of each VRAM parameters entry
Mulu D2,D0 ; Multiply it by the right value
Adda.l D0,A0 ; and now point to the right bpp entry
@Exit ; <LW14>
Rts ; <LW14>
@BadExit
Move.w (Sp)+,D2 ; Restore D2 <LW14>
Lea CivicVidInTable+4,A0 ; Point to a bad entry in the table <LW14>
Bra.s @Exit ; and go away. <LW14>
ENDWITH
CivicCalcMaxHeight
; This subroutine will return the maximum height for the given width, depending on which monitor one is in.
; This is only called for 1MegVRAM configurations in 16bpp
; The max width is given by:
;
; maxHeight = ( width <= 512 ? 512 : 340 )
;
; Needs: D1 = current width
;
; Returns: D0 = max height
Move.w D1,D0
Beq MaxHExit ; If width = 0, max H = 0
Move.w #512,D0 ;
Cmp.w D0,D1 ; Is width <= then 512
Ble MaxHExit ; maxH = 512 else
Move.w #340,D0 ; maxH = 340
MaxHExit Rts ; go back
CVidInBad ; <LW17> #1084366
; <LW17> #1084366
; Need to restore the scratch registers and then call CivicCtlBad <LW17> #1084366
Move.w scratch(A3),saveVidInMode(A3) ; restore our Video-in mode <LW17> #1084366
MOVEM.L (SP)+, A4-A6/D3-D7 ; restore registers <LW17> #1084366
BRA.S CivicCtlBad ; go say we don't do this <LW17> #1084366
CivicSetVidInRect
;---------------------------------------------------------------------
;
; Set the Video-in parameters in Civic to the values specified in
; the rect passed to the routine.
;
; Entry: A1 = Ptr to AuxDCE
; A2 = Ptr to cs parameter record
; A3 = Ptr to private storage (CivicVidPrivates)
;
; Used: A4 = scratch Ptr to VidParams ( restored)
; A5 = scratch Ptr to VDACBase (restored)
; D6 = Actual Graphics HAL
; D7 = Actual Graphics HFP
;
;---------------------------------------------------------------------
WITH CivicVidPrivates, CivicVidParams, CivicRecord, VDVidInRect
Tst.w csPage(A2) ; only page zero is valid
Bne.s CivicCtlBad ; => not a valid page
MOVEM.L A4-A6/D3-D7,-(SP) ; Save scratch registers
;
; Get the actual values for HAL and HFP. They are not the ones in the s-resource because they
; might've changed due to a VidInMode call.
;
Move.l saveVDACBase(A3), A5 ; Get a pointer to CLUT/DAC
Move.l saveVidPtr(A3),A4 ; Get a pointer to the video params.
Btst #videoInEnb,GFlags(A3) ; If video-in is not enabled
Beq VidInCtlBad ; then return error.
Bsr CivicChkVidInRect ; check rect values and return empty rect if illegal: 1. if not valid rect. 2. if rect too big for video
Bne CVidInRectBad ; If illegal rect return error (restore scratch registers) <LW17> #1084366
; Start of subroutine... (Reverse order 'cause stacks grows down.
Move.w (csRect+right)(A2),-(SP) ; right
Move.w (csRect+bottom)(A2),-(SP) ; bottom
Move.w (csRect+left)(A2),-(SP) ; left
Move.w (csRect+top)(A2),-(SP) ; Move top to stack
Jsr CivicSetVidRectJSR ; Go do the work
Bne CVidRectBad ; got an error
Move.w (SP)+,(csRect+top)(A2)
Move.w (SP)+,(csRect+left)(A2)
Move.w (SP)+,(csRect+bottom)(A2)
Move.w (SP)+,(csRect+right)(A2)
;
; Move the rect values into our vidin privates
;
Move.w (csRect+top)(A2),currentTop(a3) ; top
Move.w (csRect+left)(A2),currentLeft(a3) ; left
Move.w (csRect+bottom)(A2),currentBottom(a3) ; bottom
Move.w (csRect+right)(A2),currentRight(a3) ; right
Move.l #vCivicVidInBase,csBaseAddr(A2) ; Stuff the video-in base address
; Go home.
;
CVidInGoHome
VidInCtlGood
; Restore registers and exit
MOVEM.L (SP)+,A4-A6/D3-D7 ; restore registers
BRA.S CivicCtlGood ; go say we didn't have any errors
CVidRectBad
Move.w (SP)+,(csRect+top)(A2)
Move.w (SP)+,(csRect+left)(A2)
Move.w (SP)+,(csRect+bottom)(A2)
Move.w (SP)+,(csRect+right)(A2)
CVidInRectBad ; <LW17> #1084366
VidInCtlBad
;
; Need to restore the scratch registers and then call CivicCtlBad
MOVEM.L (SP)+, A4-A6/D3-D7 ; restore registers
BRA.S CivicCtlBad ; go say we don't do this
CivicChkVidInRect
;-------------------------------------------------------------
; Routine to check that a given Rect into SetVidInRect is kosher
;-------------------------------------------------------------
; This routine will check that the given rect is a valid rect
; There are 2 cases:
; 1. The Rect itself is invalid (right < left and/or botoom < top) return empty rect
; 2. The Rect is invalid because left or top are < 0.
; 2. The desired rect is greater than the max video-in rect allowed. Look at the monitor tables.
; 3. If in 8bpp-video in and graphics 8,4,2,1, then rect has to obey following rules:
; a. left has to be even (bit 0) == 0
; b. width has to be MOD 4 (bit 1,0) == 0;
; Uses: D0/D1/D2/D3
Clr.b D2 ; Used as a flag
Move.w (csRect+top)(A2),D0 ; Get the top edge of the rect
Bmi VidInNegativeRect ; If it's negative, return a -1 rect
Move.w (csRect+bottom)(A2),D1 ; and the bottom edge
Bmi VidInNegativeRect ; If it's negative, return a -1 rect
Cmp.w D0,D1 ; and see if the bottom edge is less
Ble VidInZeroRect ; return error with a zero rect
Move.w (csRect+left)(A2),D0 ; Get the left edge of the rect
Bmi VidInNegativeRect ; If it's negative, return a -1 rect
Move.w (csRect+right)(A2),D1 ; and the right
Bmi VidInNegativeRect ; If it's negative, return a -1 rect
Cmp.w D0,D1 ; and see if the right edge is less
Ble VidInZeroRect ; return error with a zero rect
; If the video is in 8bpp, make sure that the window width is MOD4 and the left is
; on an even bit. A5 contains the pointer to Sebastian
Move.b SebastPCBR(A5), D3 ; Get the PCBR Value
Btst #fCivicVidInBpp,D3 ; Are we in 16bpp
Bne VidRectOK
Sub.w D0,D1 ; calculate the width of the csRect
Btst #0,D0 ; Is the left edge on an even pixel
Beq CheckWidth
Bclr #0,D0 ; Make it even
Move.w D0,(csRect+left)(A2) ; and write it back out
Move.w (csRect+right)(A2),D1 ; Calculate the new width with the new left edge
Sub.w D0,D1 ; store the width in D1
Moveq #1,D2 ; Set up a flag that says we modifed csRect
CheckWidth
Btst #0,D1 ; Is the width even
Bne MakeRectMod4 ; if not, make it
Btst #1,D1 ; and also mod 4
Bne MakeRectMod4 ; if not, make it
Tst.b D2 ; Did we modify the left edge
Beq VidRectOK ; nope
Bra.s VidInRectMod ;
MakeRectMod4
Bclr #0,D1 ; make it even
Bclr #1,D1 ; and mod 4
Add.w (csRect+left)(A2),D1 ; Add the left edge to the width
Move.w D1,(csRect+right)(A2) ; and write it back out
Bra.s VidInRectMod
VidInNegativeRect
Move.w #-1,D0 ; Prepare to return a -1 rect
Move.w D0,(csRect+left)(A2) ; Returns a -1 rect to indicate
Move.w D0,(csRect+right)(A2) ; that the original rect was illegal
Move.w D0,(csRect+top)(A2)
Move.w D0,(csRect+bottom)(A2)
Bra.s VidInRectMod ; Return an error
VidInZeroRect
Clr.w (csRect+left)(A2) ; Returns a zero rect to indicate
Clr.w (csRect+right)(A2) ; that the original rect was illegal
Clr.w (csRect+top)(A2)
Clr.w (csRect+bottom)(A2)
VidInRectMod
Moveq #1,D0 ; Show that something went wrong
Bra.s CkVidRectExit
VidRectOK
Moveq #0,D0 ; For now, return a "good" value
CkVidRectExit
Rts
EndWith
CivicSetAltSense
;---------------------------------------------------------------------
;
; SetAltSense sets up the alternate senseID pRam byte to contain
; a valid ÒindexÓ code if a valid sense code is passed
; in csMode (byte 0 is the sense code, byte 1 is the type).
;
; A1 = Ptr to AuxDCE/Ptr to MonIDs table (not restored)
; A2 = Ptr to cs parameter record
; A3 = Ptr to private storage
;
;---------------------------------------------------------------------
With spBlock,CivicVidPrivates,SP_Params
;
; First, set up a slot parameter block on the stack.
;
Suba #spBlockSize,Sp ; Make an SpBlock on the stack.
Move.l Sp,A0 ; Get a pointer to it into A0.
Move.b dCtlSlot(A1),spSlot(A0) ; Set it up.
Clr.b spExtDev(A0)
;
; Next, read the current pRam so that we can set it appropriatelyÉ
;
Suba #SizesPRAMRec,Sp ; Make an sPRAM block on the stack.
Move.l Sp,spResult(A0) ; Point to it.
_sReadPRamRec ; Get pRAM.
;
; See what we need to doÉ
;
Move.b csMode+1(A2),D0 ; Get the sense-code type.
Beq.s @NoConnect ; If indexed (0), use type 7.
Cmp.b #indexedSense2P,D0 ; If we got a type 3,
Beq.s @2PExtended ; then go there.
Cmp.b #indexedSenseHR,D0 ; If we got a type 6,
Beq.s @HRExtended ; then go there.
Cmp.b #indexedNoConnect,D0 ; If we got a type 7,
Beq.s @NoConnect ; then go there.
Bra @MonIDNotValid ; Otherwise, return an error.
@2PExtended
Move.b csMode(A2),D1 ; Get the sense code into D0.
Cmp.b #extended2PRdRGB,D1 ; If itÕs the Radius ColorTPD,
Beq @WriteIt ; then write it out.
Cmp.b #extended2PRdMono,D1 ; If itÕs the Radius MonoTPD,
Beq.s @WriteIt ; then write it out.
Bra @MonIDNotValid ; Otherwise, return an error.
@HRExtended
Cmp.b #extendedHR,csMode(A2) ; If itÕs not the MultiSync code,
Bne @MonIDNotValid ; return an error.
Move.b #indexedSenseHR,D1 ; Otherwise, default to HR.
Bra.s @WriteIt
@NoConnect
Move.b csMode(A2),D1 ; Get the monID.
Cmp.b #indexedNoConnect,D1 ; If itÕs one of the no-connect codes,
Beq.s @ClearIt ; then zero-out the no-connect pRam byte.
Cmp.b #extendedNoConnect,D1 ;
Beq.s @ClearIt ;
Lea CivicMonIDs,A1 ; Get ptr to MonIDs table.
Move.w (A1)+,D0 ; Get count of modes.
@ValidLoop Move.b (A1)+,D1 ; Get an ID from the table.
Cmp.b csMode(A2),D1 ; If we have a match,
Beq.s @FoundMatch ; say so.
Dbra D0,@ValidLoop ; Otherwise, keep looping thru
Bra.s @MonIDNotValid ; table until no match is found.
@FoundMatch Tst.b csMode+1(A2) ; If this is not an extended code,
Beq.s @WriteIt ; then just do write.
Cmp.b #extendedSenseVGA,D1 ; Is it the VGA code?
Bne.s @TryPal ; Nope, try PAL.
Move.b #indexedSenseVGA,D1
Bra.s @WriteIt
@TryPal Cmp.b #extendedSensePAL,D1 ; Is it the PAL code?
Bne.s @TryPALBox ; Nope, try PAL encoder box.
Move.b #indexedSensePAL,D1
Bra.s @WriteIt
@TryPALBox Cmp.b #extendedSensePALBox,D1 ; Is it the PAL encoder box code?
Bne.s @TryNTSC ; Nope, try NTSC encoder box.
Move.b #indexedSensePAL,D1
Bra.s @WriteIt
@TryNTSC Cmp.b #extendedSenseNTSC,D1 ; Is it the NTSC encoder box code?
Bne.s @TryGF ; Nope, try GoldFish.
Move.b #indexedSenseNTSC,D1
Bra.s @WriteIt
@TryGF Cmp.b #extendedSenseGF,D1 ; Is it the GoldFish?
Bne.s @Try19 ; Nope, try 19Ó.
Move.b #indexedSenseGF,D1 ;
Bra.s @WriteIt
@Try19 Cmp.b #extendedSense19,D1 ; Is it a 19Ó?
Bne.s @WriteIt ; Nope, must be indexed.
Move.b #indexedSense19,D1
@WriteIt Move.b D1,SP_AltSense(Sp) ; Write out ÒindexÓ to pRam record.
Ori.b #spAltSenseValidMask,SP_AltSense(Sp) ; Validate it.
Bra.s @WritePRam
@ClearIt Clr.b SP_AltSense(Sp) ; Invalidate no-connect byte.
@WritePRam Move.l Sp,spsPointer(A0) ; Set up to whack pRam.
_sPutPRAMRec ; Whack it.
Adda #SizesPRAMRec+spBlockSize,Sp ; Restore stack andÉ
Bra CivicCtlGood ; Éleave.
@MonIDNotValid Adda #SizesPRAMRec+spBlockSize,Sp ; Restore stack andÉ
Bra CivicCtlBad ; Éleave with error.
Endwith
CivicSetRGBByPass
;---------------------------------------------------------------------
;
; This routine will do switch the frame buffer from RGB out to Composite out.
; In order to do this, it has to find the sresource that has the timing
; for NTSC or PAL, depending on the csType; it should delete the current
; sresource, insert it back as disabled, insert the NTSC/PAL one as enabled
; and reprogram Civic with these new values.
;
; VDCompositeFlagPtr: csMode [byte] 0: RGB Out, 1: Composite Out
; csStandard [byte] 0: NTSC, 1: PAL
; csConv [byte] 0: NonConvolved, 1: Convolved
;
; Entry: A1 = Ptr to AuxDCE
; A2 = Ptr to cs parameter record
; A3 = Ptr to private storage (CivicVidPrivates)
;
; Used: A4 = scratch Ptr to VidParams ( restored)
; A5 = scratch Ptr to VDACBase (restored)
;
;---------------------------------------------------------------------
With VDCompositeOut,SPBlock,CivicFrame,CivicRecord,CVidInBPPRec
MOVEM.L A4-A7/D3-D7,-(SP) ; Save scratch registers
Move.w GFlags(A3),scratch(A3) ; Save our gflags for error exit
Move.l saveVidPtr(A3),A4 ; Get a Pointer to our current vidparams
Tst.b csMode(A2) ; Are we enabling composite out
Bne @SetCompositeSync ; Yes, go get the Composite VidParams.
; The call is to switch to drive to RGB, so first check to see if we're already doing it.
; If not, then there are two cases we have to look out for:
;
; 1. We are driving an interlaced display already. In this case saveRGBSlotId == 0 and
; the cvpScanCtl byte is 1. Just go and switch the bypass signal.
;
; 2. We need to drive a progressive scan display. In this case, the saveRGBSlotId ­ 0 and
; we need to get it and switch to it. (First we need to test if video-in was changed
; since the switch to composite and adjust the spID accordingly). We also then clear saveRGBSlotId.
;
@SetRGBSync
; First, check to see whether we are already driving RGB out:
Move.w GFlags(A3),D5 ; Get our gflags
Btst #CompositeSyncOn,D5 ; Look at our composite/RGB flag
Beq CBypassExit ; Already driving RGB
Bclr #CompositeSyncOn,D5 ; Say we are driving RGB
Move.w D5,GFlags(A3) ; and save it in our flags
; Now, check to see if we are supposed to drive an interlaced monitor (in which case we don't need to reprogram Civic)
Move.l #0,D3 ; MMC clock selects RGB Syncs
Move.b saveRGBSlotId(A3),D2 ; Do we have a 2nd slotID saved?
Beq.s @CheckInterlaced ; we don't if we originally had an interlaced disp through RGB)
; Set GFlags to reflect monochrome-only displays.
;
@SwitchSyncToRGB
Cmp.w #indexedSenseFP,saveMonID(A3) ; If this is a Mono-Only Full Page,
Beq.s @SetMonoFlags ; then say so.
Cmp.w #indexedSense2P,saveMonID(A3) ; If this is a Mono-Only Two-Page,
Beq.s @SetMonoFlags ; then say so.
Bra.s @AllDone ; Otherwise, skip.
@SetMonoFlags Bset #IsMono,GFlags(A3) ; Turn on the IsMono and
Bset #GrayFlag,GFlags(A3) ; GrayFlag flags.
@AllDone
;
; In order to avoid driving the wrong timing into the composite monitor switch the bypass to RGB:
;
; Move.l saveYMCABaseAddr(A3),A0 ; MMC Clock Select. <LW19>
; Move.l #0,MMC_Bypass(A0) ; Switch to RGB Syncs <LW19>
Bra @GoSwitchMonitorsFromComposite ; We do, so go switch back to the correct monitor.
@CheckInterlaced
Tst.b cvpScanCtl(A4) ; Are our RGB Sync parameters for an interlaced display (1 = interlaced)
Bne CBypassQuick ; if so, then just switch mickey and turn on syncs
Bra CBypassExit ; Else, we don't know what monitor to drive.
; The call is to switch to drive Composite, so first check to see if we're already doing it.
; If not, then there are two cases we have to look out for:
;
; 1. We are driving an interlaced display already. In this case
; the cvpScanCtl byte is 1. Just go and switch the bypass signal.
;
; 2. We are driving a progressive scan display. In this case, save the current spID
; and get the desired switch ID from the vidparams and switch.
;
@SetCompositeSync
; First, check to see if we are already driving composite out:
Move.w GFlags(A3),D5 ; Get our gflags
Btst #CompositeSyncOn,D5 ; Look at our composite flag
Bne.s @AlreadyDrivingSync ; Don't need to save the spID
Move.b saveSlotId(A3),saveRGBSlotId(A3); Save our current slot ID so we can return to this monitor.
Bset #CompositeSyncOn,D5 ; If not, set the bit and
Move.w D5,GFlags(A3) ; save our internal flags
@AlreadyDrivingSync
Move.l #-1,D3 ; MMC clock select variable in D3
; When we get here, then we know that we should drive composite out and that our current display is not interlaced.
; Get the equivalent spID for NTSC/PAL out, depending on the selector csStandard
Tst.b csStandard(A2) ; Do we want NTSC or PAL
Beq.s @GetNTSC ; if 0, then we want NTSC
Tst.b csConv(A2) ; Do we want Convolution ON
Beq.s @GetPALNonConv ; if 1, then we want conv on
Bset #ConvolutionOn,D5 ; Say we are driving with convolution
Move.b cvpConvPALID(A4),D2 ; Get it in D2
Beq CBypassBad ; If it's zero, we can't do this.
Bra.s @SetPALFlag ; and carry on
@GetPALNonConv
Bclr #ConvolutionOn,D5 ; Say we are NOT driving with convolution
Tst.b saveSizeVRAM(A3) ; Load the correct spID depending on how much VRAM we have
Bne.s @1 ; branch if we have 2 megs
Move.b cvpPALID1Meg(A4),D2 ; Get the 1Meg spID
Beq CBypassBad ; If it's zero, we can't do this.
Bra.s @SetPALFlag ; Carry on
@1
Move.b cvpPALID2Meg(A4),D2 ; Get the 2Meg spID
Beq CBypassBad ; If it's zero, we can't do this.
* Bra.s @SetPALFlag ; Carry on
@SetPALFlag
Bclr #NTSCTimingOn,D5 ; Say we are driving PAL
Bra.s @GoSwitchMonitorsFromRGB ; Go Switch the monitor timing
@GetNTSC
Tst.b csConv(A2) ; Do we want Convolution ON
Beq.s @GetNTSCNonConv ; if 1, then we want conv on
Bset #ConvolutionOn,D5 ; Say we are driving with convolution
Move.b cvpConvNTSCID(A4),D2 ; Get it in D2
Beq CBypassBad ; If it's zero, we can't do this.
Bra.s @SetNTSCFlag ; and carry on
@GetNTSCNonConv
Bclr #ConvolutionOn,D5 ; Say we are NOT driving with convolution
Tst.b saveSizeVRAM(A3) ; Load the correct spID depending on how much VRAM we have
Bne.s @2 ; branch if we have 2 megs
Move.b cvpNTSCID1Meg(A4),D2 ; Get the 1Meg spID
Beq CBypassBad ; If it's zero, we can't do this.
Bra.s @SetNTSCFlag ; and carry on
@2
Move.b cvpNTSCID2Meg(A4),D2 ; Get the 2Meg spID
Beq CBypassBad ; If it's zero, we can't do this.
* Bra.s @SetNTSCFlag ; and carry on
@SetNTSCFlag
Bset #NTSCTimingOn,D5 ; say we are driving NTSC
; Disable the sync outputs to avoid driving them with the new interlaced parameters.
@GoSwitchMonitorsFromRGB
Move.w D5,GFlags(A3) ; save our internal flags
Bclr #IsMono,GFlags(A3) ; Turn off the IsMono and
Bclr #GrayFlag,GFlags(A3) ; GrayFlag flags.
@GoSwitchMonitorsFromComposite
; Save our current video-in bpp and state of the overlay enable bit so we can change it
; after the switch. (The DynamicSwitch routine will set it to the vidparams value for
; the PCBR, mainly overlay off and vid-in @ 8bpp).
Move.l saveVDACBase(A3), A5 ; Get the a pointer to CLUT/DAC
Move.b SebastPCBR(A5),D5 ; Store the current value
Andi.b #$88,D5 ; Clear all except overlay and vin bpp
dRead_Civic #VDCEnb,D7 ; Get the state of the VDCEnable bit in Civic
Move.w d7,-(SP) ; and save it.
dRead_Civic #VDCClk,D7 ; Get the state of the VDCClk
Move.w d7,-(SP) ; and save it.
Jsr DynamicSwitch ; Do the switch dynamically
Bne CBadMode ; Probably max mode < current mode
Move.w (Sp)+,D7 ; Get the saved VDCClk
dWrite_Civic D7,#VDCClk ; Write it out
Move.w (Sp)+,D7 ; Get the saved VDCEnb
dWrite_Civic D7,#VDCEnb ; Write it out
; Switch Mikey to drive out the correct port (RGB or Composite)
Move.l saveYMCABaseAddr(A3),A0 ; MMC Clock Select.
Move.l D3,MMC_Bypass(A0) ; Select the desired input clock, depending if we are
; going to RGB or to Composite
Move.l saveCivicBase(A3),A0 ; Point to the base of Civic.
Move.l D3,Civic_SyncClr(A0) ; Disable/Enable Sync outputs.
MOVEM.L (SP)+,A4-A7/D3-D7 ; restore registers
Move.w saveMode(a3),D2 ; get our current mode so the VidModeGuts
Move.w saveMode(a3),D1 ; get our current mode so the VidModeGuts
Sub.w #FirstVidMode,D1 ; Make mode zero-based.
Jsr CivicSetVidModeGuts2
Clr.l d0 ; Say we had no errors
BRA.S CivicCtlGood ; go say we didn't have any errors
; if VideoIn is enabled, we have to calculate the new video-in horiz/vert values
;
Move.w GFlags(A3),D0 ; Get our local flags to see
Btst #videoInEnb,D0 ; if video in is enabled
Beq.s CBypassExit ; if not, we don't have to adjust the video-in parameters
; Switch the CLUT/DACÕs depth.
;
Move.b SebastPCBR(A5),D7 ; Get the new programmed value
Andi.b #$77,D7 ; Clear the overlay enable and the vin bpp values
Or.b D5,D7 ; Get the saved ovly, vin bpp
Move.b D7,SebastPCBR(A5) ; Change the depth.
Jsr CSetVidInModeGuts ; Adjust the horizontal parameters
Movem.l A3-A5/D2-D7,-(Sp) ; Save our registers
Move.l saveVidPtr(A3),A4 ; Get a pointer to the vidParams.
Move.l saveVDACBase(A3), A5 ; Get the a pointer to CLUT/DAC
Move.w currentRight(a3),-(SP) ; Get the current video in rect
Move.w currentBottom(a3),-(SP) ;
Move.w currentLeft(a3),-(SP) ;
Move.w currentTop(a3),-(SP) ; in reverse order
Jsr CivicSetVidRectJSR ; Go do the work
Adda #8,SP ; Clean up the stack
Movem.l (Sp)+,A3-A5/D2-D7 ; Restore our registers
Jsr CivicReset ; Reset Civic (Needs A3 = vidprivates, trashes A0)
; Restore registers and exit
CBypassExit
MOVEM.L (SP)+,A4-A7/D3-D7 ; restore registers
BRA.S CivicCtlGood ; go say we didn't have any errors
CBadMode
Adda #4,SP ; Clean up the stack
Move.w d0,csMode(A2) ; return the max mode
CBypassBad
Move.w scratch(A3),GFlags(A3) ; restore our gflags
MOVEM.L (SP)+,A4-A7/D3-D7 ; restore registers
BRA.S CivicCtlBad ; go say we don't do this
ENDWITH
CBypassQuick
Move.l saveYMCABaseAddr(A3),A5 ; MMC Clock Select.
Move.l D3,MMC_Bypass(A5) ; Select the desired input clock, depending if we are
Move.l saveCivicBase(A3),A0 ; Point to the base of Civic.
Move.l D3,Civic_SyncClr(A0) ; Disable/Enable Sync outputs.
Bra.s CBypassExit
CBypassNoGo
Move.w scratch(A3),GFlags(A3) ; restore our gflags
Bra.s CBypassExit
CNoRGBSwitchExit
Move.w scratch(A3),GFlags(A3) ; restore our gflags
Bra.s CBypassExit
;---------------------------------------------------------------------
;
; This routine that will disable the current spID s-resource and
; enable a new spID as the current, enabled s-resource, and will change
; the vidparms pointer to it's parameters. It will then reprogram Civic
; to drive the new parameters.
;
;
; Entry: D2 = spID of the desired new monitor
;
; Exit: D0 = status
;
;---------------------------------------------------------------------
With VPBlock,SpBlock,CivicRecord
DynamicSwitch
MOVEM.L A0-A7/D1-D7,-(SP) ; Save scratch registers
SUBA #spBlockSize,SP ; make a slot parameter block
MOVE.L SP,A0 ; get pointer to block in A0
Clr.b spSlot(A0) ; Look at slot 0
Clr.b spID(A0) ; Start looking at spID 0,
Clr.b spExtDev(A0) ; no external devices.
Clr.b spTBMask(A0) ; Only look for the board sRsrc.
Move.w #catBoard,spCategory(A0) ; Look for: catBoard,
Move.w #typBoard,spCType(A0) ; typBoard,
Clr.w spDrvrSW(A0) ; 0,
Clr.w spDrvrHW(A0) ; 0.
Clr.l spParamData(A0) ; (The board sRsrc must be enabled.)
Bset #foneslot,spParamData+3(A0) ; Limit search to slot 0.
_GetTypeSRsrc ; Get the spsPointer.
Bne CNoSwitch ; If an error, then bail out
MOVE.B #sVidParmDir,spID(A0) ; look for the video parameters dir
_sFindStruct ; Try to load it.
Bne CNoSwitch ; If an error, then bail out
MOVE.B D2,spID(A0) ; look in the directory for this config's parameters
_sGetBlock ; Try to load it.
Bne CNoSwitch ; If an error, then bail out
MOVE.L spResult(A0),A5 ; get pointer to it
;
; Look into the vidparams and see if we can support the current mode. If not,
; return an error with the max mode we can support.
;
; Get the current mode and see if our new resolution can support it, then return the
; zero-based video mode into D1
Clr.w D0 ; make sure byte is cleared
Move.b cvpMaxGraphMode(A5),D0 ; Read the max value for this configuration.
Cmp.w saveMode(A3),D0 ; Is our max mode greather than or equal
Bhs.s @ModeIsOK ; the current mode, if so, then go on
Move.b d0,d1 ; save our max mode
Move.l a5,a0
_DisposPtr
Move.b d1,d0 ; save our max mode
Andi.l #$000000FF,d0 ; make the return status be the max mode
Bra CSwitchBadMode ; return with D0 = max mode for the selected spID
@ModeIsOK
Clr.w D0 ; make sure byte is cleared <LW19>
Move.b cvpMaxVidInMode(A5),D0 ; Read the max value for this configuration. <LW19>
Subi.w #FirstVidMode,D0 ; make it zero based <LW19>
Cmpi.w #3,d0 ; Is the maximum video-in 8bpp <LW19>
bne.s @VidInOK ; nope, so no danger here <LW19>
Cmp.w #16,saveVidInMode(A3) ; Is our current vid in mode 16bpp <LW19>
bne.s @VidInOK ; nope, so we are in gray and going to a gray only display <LW19>
Move.l a5,a0 ; Get our pointer <LW19>
_DisposPtr ; <LW19>
Move.l #8,d0 ; report back our max vid-in mode <LW19>
Bra CSwitchBadMode ; return with D0 = max mode for the selected spID <LW19>
@VidInOK ; OK, VidMode and VidInMode are OK, so load the new spID <LW19>
; Delete the Current spID
Move.b saveSlotId(A3),spID(A0) ; Get the slotID
Clr.b spSlot(A0) ; Look at slot 0
Clr.b spExtDev(A0) ; no external devices.
_SDeleteSRTRec
Bne CNoSwitch ; If an error, then bail out
; Is the new s-resource already in the slot resource table? <LW17> #1084628
; Try to enable it, and if we get an error, then it wasn't in the table, so we need to insert it <LW17> #1084628
; <LW17> #1084628
Move.b D2,spID(A0) ; Get the spID that is in D2 <LW17> #1084628
Clr.b spSlot(A0) ; Look at slot 0 <LW17> #1084628
Clr.b spExtDev(A0) ; no external devices. <LW17> #1084628
Clr.l spParamData(A0) ; we want it enabled <LW17> #1084628
_SetSRsrcState ; <LW17> #1084628
Bne.s @InsertspID ; If no error, then get the base <LW17> #1084628
; <LW17> #1084628
; Delete the sRsrc so that we can insert it and the DCE fields get updated appropriately <LW17> #1084628
; <LW17> #1084628
_SDeleteSRTRec ; <LW17> #1084628
Bne CNoSwitch ; If an error, then bail out <LW17> #1084628
; <LW17> #1084628
; Insert the new s-resource, enabled ; <LW17> #1084628
@InsertspID ; <LW17> #1084628
Clr.l spsPointer(A0) ; spsPointer needs to be nil
Move.b D2,spID(A0) ; Get the spID that is in D2
Move.w dCtlRefNum(A1),spRefNum(A0) ; Get the driver's ref num so DCE gets updated.
Clr.l spParamData(A0) ; we want it enabled
_InsertSRTRec ; do it.
Bne CNoSwitch ; If an error, then bail out
; Load the "new" base address
_sFindDevBase ; Get the base address for this spID
Bne CNoSwitch ; If an error, then bail out
Move.l spResult(A0),D3 ; Move the base address.
Move.l D3,saveBaseAddr(A3) ; save our new base address
Lsr.l #5,D3 ; Normalize it for Civic
Andi.l #$FF,D3 ; Only 8 bits are valid
; Get the new offset and mode where it happens
Move.w #SixthVidMode,D1 ; Start at 32bpp
@LookForOffset
Move.b dCtlSlot(A1),spSlot(A0) ; Look at this slot
Clr.b spExtDev(A0) ; and no ExtDev
Move.b dCtlSlotID(A1),spID(A0) ; Put spID into spBlock.
_SRsrcInfo
Bne CNoSwitch ; If failed, quit.
Move.b D1,spID(A0) ; Look for this mode
_SFindStruct
Beq.s @ModeExists ; If noErr, then get block
Cmp.w #-330,D0 ; Did we get a smBadRefID
Bne CNoSwitch ; No, then quit.
Subi.w #1,D1 ; Look for next lower mode
bra.s @LookForOffset ;
@ModeExists
Move.b #mVidParams,spID(A0) ; Look for the video-parameters block
_SGetBlock
Bne CNoSwitch ; If failed, quit.
Move.l spResult(A0),a4 ; save the pointer to the block
Move.L vpBaseOffset(A4),d0 ; Get Offset
Beq.s @GotOffset ; If zero, then we have our offset stored in privates
Move.l d0,saveBaseAddrOffset(A3) ; Store non-zero offset in our privates
DBRA d1,@LookForOffset ; look at next lower mode
@GotOffset
Addi.w #1,d1 ; Adjust mode that has the non-zero offset
move.w d1, saveNewBaseMode(A3) ; and save it in our privates
; Release our spBlock
Adda #spBlockSize,Sp ; Clean up the stack.
; Save current spID in our globals, so that we can restore it when they switch from Composite to RGB
Move.l saveVidPtr(A3),A0 ; Get a Pointer to our current vidparams
_DisposPtr ; and dispose of it so we can load the new one
Move.l A5,saveVidPtr(A3) ; save it our globals
Move.l A5,A4 ; and in our scratch register
Move.b D2,saveSlotID(A3) ; save the new slot ID
; Now do the same code that primary init does in setting up video
Jsr CivicChangeHardware ; Reprogram Civic
MOVEM.L (SP)+,A0-A7/D1-D7 ; restore registers
Clr.l D0 ; return good status
CSwitchExit
RTS ; go say we didn't have any errors
CSwitchBadMode
Adda #spBlockSize,Sp ; Clean up the stack's spBlock;
MOVEM.L (SP)+,A0-A7/D1-D7 ; restore registers
Bra.s CSwitchExit ; and return.
CNoSwitch
Adda #spBlockSize,Sp ; Clean up the stack's spBlock;
MOVEM.L (SP)+,A0-A7/D1-D7 ; restore registers
Moveq.l #-1,D0 ; return bad status.
Bra.s CSwitchExit ; and return.
;---------------------------------------------------------------------
;
;
;---------------------------------------------------------------------
CivicChangeHardware
Move.w Sr,-(Sp) ; Save current interrupt level
Bsr CivicWaitVSync ; Wait for the next VBL.
dWrite_Civic #0,#Enable ; Disable Casio (the timing generator).
Move.l saveCivicBase(A3),A0 ; Point to the base of Civic.
; Set up to generate a stable raster.
;
dWrite_Civic #0,#ConvEnb ; Clear convolution before selecting progressive/interlaced display.
Move.b cvpFlags(A4),D2 ; Pick up the Video-in parameter parameter.
beq.s @NoVideoIn ; We don't want video-in enabled.
dWrite_Civic #0,#BusSize ; We do here, so program Civic and
Bra.s @SetupScanCtl ; and do the Scan Ctl stuff.
@NoVideoIn
dWrite_Civic #1,#BusSize ; We don't have video-in here, so program Civic and
@SetupScanCtl
Move.b cvpScanCtl(A4),D2 ; Pick up the ScanCtl parameter.
dWrite_Civic D2,#ScanCtl ; Write it out.
Move.b cvpConvEnb(A4),D2 ; Pick up the ConvEnb parameter.
dWrite_Civic D2,#ConvEnb ; Write it out.
Move.l #Endeavor,A0 ; Point to the VidClk.
;
; determine is we have a Clifton or Endeavor by writing to Endeavor M and reading it back
Cmp.b #BoxCentris660AV,saveBoxFlag(A3) ; Do we have a Tempest25 <SM18>
beq.s @DoClifton ; Éyes, program Clifton
Cmp.b #BoxTempest33,saveBoxFlag(A3) ; Do we have a Tempest33
beq.s @DoClifton ; Éyes, program Clifton
Move.b cvpEndeavorClk(A4),D0 ; Get the input clock source.
Bne.s @Use17MHz ; If one, use the 17MHz clock.
Moveq.l #0,D0 ; Set up to select the 14MHz clock.
Bra.s @SelClk ;
@Use17MHz Moveq.l #-1,D0 ; Set up to select the 17MHz clock.
@SelClk Move.l saveYMCABaseAddr(A3),A5 ; Otherwise, get a pointer to MMC.
Move.l D0,MMC_ClockSelect(A5) ; Select the desired input clock.
Clr.b EndeavorClk(A0) ; Always select Clk A.
Move.b cvpEndeavorM(A4),EndeavorM(A0) ; Program M.
Move.b cvpEndeavorN(A4),EndeavorN(A0) ; Program N.
bra.s @ProgramCivic
@DoClifton
Move.l A4,-(Sp) ; Save our scratch address <LW17> #PUMA
Bsr IsItPUMA ; Test to see if it's a PUMA ( if CC ­ 0, then Clifton) <LW17> #PUMA
Bne.s @ItsClifton ; It's a Clifton <LW17> #PUMA
Adda.l #(cvpPumaW-cvpCliftonW),A4 ; Adjust our video parameters with the correct offset <LW17> #PUMA
@ItsClifton ; <LW17> #PUMA
Move.b cvpCliftonClk(A4),D0 ; Get the input clock source.
Bne.s @Use17MHz2 ; If one, use the 17MHz clock.
Moveq.l #0,D0 ; Set up to select the 14MHz clock.
Bra.s @SelClk2 ;
@Use17MHz2 Moveq.l #-1,D0 ; Set up to select the 14MHz clock.
@SelClk2 Move.l saveYMCABaseAddr(A3),A5 ; Otherwise, get a pointer to MMC.
Move.l D0,MMC_ClockSelect(A5) ; Select the desired input clock.
; Writes to Clifton:
; D0: Contains the word written out, with %000000? (with ? being the bit for Clifton)
; D1: Contains the bits we want to serially write out
; D2: Contains the loop counter for all the bits
;
; Load the Clifton Control register to enable the MUX and the PROGram register
move.l #ControlWordSize-1,D2 ; Get the loop counter
move.l #LoadCliftonControl,D1 ; Enable MuxRef/Enable PROG Register
@LoadPROG
Move.l #1,D0 ; Set up the mask for the bit
And.l D1,D0 ; Transfer the first bit to D0
Move.b D0,EndeavorM(A0) ; write the bit out to Clifton
lsr.l #1,D1 ; get the next bit
Dbra D2,@LoadPROG ; Éfor the whole word
; Load the Frequency register
move.b cvpCliftonWSize(A4),D2 ; Get the size of the W Parameter
sub.b #1,D2 ; adjust loop # for dbra
extb.l D2 ; and make byte a long
move.l cvpCliftonW(A4),D1 ; And the W parameter
@LoadFreq
Move.l #1,D0 ; Set up the mask for the bit
And.l D1,D0 ; Transfer the first bit to D0
Move.b D0,EndeavorM(A0) ; write the bit out to Clifton
lsr.l #1,D1 ; get the next bit
Dbra D2,@LoadFreq ; Éfor the whole frequency
; Load the Clifton Control register to keep MUXREF enabled and disable loading of PROG Register
move.l #ControlWordSize-1,D2 ; Get the loop counter
move.l #LoadCliftonProgram,D1 ; Enable MuxRef/disable PROG Register
@DisablePROG
Move.l #1,D0 ; Set up the mask for the bit
And.l D1,D0 ; Transfer the first bit to D0
Move.b D0,EndeavorM(A0) ; write the bit out to Clifton
lsr.l #1,D1 ; get the next bit
Dbra D2,@DisablePROG ; Éfor the whole word
; Wait for 5 msec to enable the new frequency to get stable
jsr Wait5ms ; trashes D0
; Load the Clifton Control register to disable MUXREF and PROGram register.
move.l #ControlWordSize-1,D2 ; Get the loop counter
move.l #LoadCliftonMuxRef,D1 ; Disable MUXREF/disable PROG Register
@DisableMUXREF
Move.l #1,D0 ; Set up the mask for the bit
And.l D1,D0 ; Transfer the first bit to D0
Move.b D0,EndeavorM(A0) ; write the bit out to Clifton
lsr.l #1,D1 ; get the next bit
Dbra D2,@DisableMUXREF ; Éfor the whole word
Movea.l (Sp)+,A4 ; restore our address <LW17> #PUMA
@ProgramCivic
dWrite_Civic #0,#VDCEnb ; Disable VDC interrupts.
dWrite_Civic #1,#VDCClk ; Disable VDC clock.
dWrite_Civic cvpVHLine(A4),#VHLine ; Set up the vertical params.
dWrite_Civic cvpVSync(A4),#VSync ;
dWrite_Civic cvpVBPEq(A4),#VBPEq ;
dWrite_Civic cvpVBP(A4),#VBP ;
dWrite_Civic cvpVAL(A4),#VAL ;
dWrite_Civic cvpVFP(A4),#VFP ;
dWrite_Civic cvpVFPEq(A4),#VFPEq ;
dWrite_Civic cvpBusSize(A4),#BusSize ; Write the BusSize parameter
dWrite_Civic cvpHSerr(A4),#HSerr ; Write out the horizontal timing parameters.
dWrite_Civic cvpHlfLn(A4),#HlfLn ;
dWrite_Civic cvpHEq(A4),#HEq ;
dWrite_Civic cvpHSP(A4),#HSP ;
dWrite_Civic cvpHBWay(A4),#HBWay ;
dWrite_Civic cvpHAL(A4),#HAL ;
dWrite_Civic cvpHFP(A4),#HFP ;
dWrite_Civic cvpHPix(A4),#HPix ;
dWrite_Civic #$FF0,#VInHal ; For now, set the video-in paramsÉ
dWrite_Civic #$000,#VInHFPD ; Éway into the blanking period.
dWrite_Civic #$FF8,#VInHFP ;
dWrite_Civic #$FF0,#VInVal ;
dWrite_Civic #$FF8,#VInVFP ;
dWrite_Civic cvpGSCDivide(A4),#GSCDivide ; Set the framebuffer params for this depth.
dWrite_Civic cvpRowWords(A4),#RowWords ;
dWrite_Civic D3,#BaseAddr ;
dWrite_Civic cvpAdjF1(A4),#AdjF1 ;
dWrite_Civic cvpAdjF2(A4),#AdjF2 ;
dWrite_Civic cvpPipeD(A4),#PipeD ;
; Switch the CLUT/DACÕs depth.
;
Move.l saveVDACBase(A3), A5 ; Get the a pointer to CLUT/DAC
Move.w cvpSebastPCBR(A4),D0 ; Get the PCBR value
Move.b D0,SebastPCBR(A5) ; Change the depth.
; Now, reset the timing generator.
;
dWrite_Civic #1,#Enable ; Enable Casio (the timing generator).
Jsr CivicReset ; Reset Civic (Needs A3 = vidprivates, trashes A0)
Move.w (Sp)+,Sr ; Restore previous interrupt level.
Rts
ENDWITH
;---------------------------------------------------------------------
;
; SetResolution gets the video driver and the framebuffer controller
; set up for being switched to a different resolution.
;
; D1 containts the spID to the resolution (mode) to enable.
; A1 = AuxDCE POINTER
; A2 = parameter block pointer
; A3 = dCtlStorage pointer
;
; Preserves all registers
;
;---------------------------------------------------------------------
CivicSetResolution
With CivicVidParams,SpBlock,VpBlock
Movem.l D0-D1/A0/A4-A6,-(Sp) ; Save work registers.
Move.b dCtlSlotId(A1),D0 ; Remember which sRsrc to disable.
Move.b D1,dCtlSlotId(A1) ; Remember which sRsrc to enable.
; Do the Slot Manager changesÉ
;
Suba.w #spBlockSize,Sp ; Allocate a slot parameter block on the stack.
Move.l Sp,A0 ; Point to it with A0.
Clr.b spSlot(A0) ; Say that weÕre Slot $0.
Clr.b spExtDev(A0) ; DonÕt ask why, just clear this guy.
Move.b D0,spID(A0) ; Write out the spID of the sRsrc.
_SRsrcInfo ; Update our SpBlock for SUpdateSRT call below.
Move.l #1,spParamData(A0) ; Say that we want it disabled.
_SetSRsrcState ; Do it.
Move.b dCtlSlotId(A1),spID(A0) ; Write out the spID of the sRsrc.
Move.l #0,spParamData(A0) ; Say that we want it enabled.
_SetSRsrcState ; Do it.
Bne CNoSwitch ; If an error, then bail out
_SUpdateSRT ; Tell Slot Manager to update itself (it should really know, but it does not).
; Load the "new" base address
_sFindDevBase ; Get the base address for this spID
Bne CNoSwitch ; If an error, then bail out
Move.l spResult(A0),D3 ; Move the base address.
Move.l D3,saveBaseAddr(A3) ; save our new base address
Lsr.l #5,D3 ; Normalize it for Civic
Andi.l #$FF,D3 ; Only 8 bits are valid
; Get the new offset and mode where it happens
@LookForOffset
Move.b dCtlSlot(A1),spSlot(A0) ; Look at this slot
Clr.b spExtDev(A0) ; and no ExtDev
Move.b dCtlSlotID(A1),spID(A0) ; Put spID into spBlock.
_SRsrcInfo
Bne CNoSwitch ; If failed, quit.
Move.b D1,spID(A0) ; Look for this mode
_SFindStruct
Beq.s @ModeExists ; If noErr, then get block
Cmp.w #-330,D0 ; Did we get a smBadRefID
Bne CNoSwitch ; No, then quit.
Subi.w #1,D1 ; Look for next lower mode
bra.s @LookForOffset ;
@ModeExists
Move.b #mVidParams,spID(A0) ; Look for the video-parameters block
_SGetBlock
Bne CNoSwitch ; If failed, quit.
Move.l spResult(A0),a4 ; save the pointer to the block
Move.L vpBaseOffset(A4),d0 ; Get Offset
Beq.s @GotOffset ; If zero, then we have our offset stored in privates
Move.l d0,saveBaseAddrOffset(A3) ; Store non-zero offset in our privates
DBRA d1,@LookForOffset ; look at next lower mode
@GotOffset
Addi.w #1,d1 ; Adjust mode that has the non-zero offset
move.w d1, saveNewBaseMode(A3) ; and save it in our privates
; Load the ÒnewÓ video hardware setup blockÉ
;
Clr.w spID(A0) ; Start looking at spID 0, no external devices.
Clr.b spTBMask(A0) ; Only look for the board sRsrc.
Move.w #catBoard,spCategory(A0) ; Look for: catBoard,
Move.w #typBoard,spCType(A0) ; typBoard,
Clr.w spDrvrSW(A0) ; 0,
Clr.w spDrvrHW(A0) ; 0.
Clr.l spParamData(A0) ; (The board sRsrc must be enabled.)
Bset #foneslot,spParamData+3(A0) ; Limit search to slot 0.
_GetTypeSRsrc ; Get the spsPointer.
Move.b #sVidParmDir,spID(A0) ; Look for the video parameters dir.
_sFindStruct ; Load it.
Move.b dCtlSlotId(A1),spID(A0) ; Look in the directory for this config's parameters.
_sGetBlock ; Load it.
Move.l spResult(A0),-(Sp) ; Save the new privates.
Movea.l saveVidPtr(A3),A0 ; Point to the old privates.
_DisposPtr ; Dispose them.
Move.l (Sp)+,saveVidPtr(A3) ; Start using the new ones.
Adda.w #spBlockSize,Sp ; De-allocate the slot parameter block.
; Change the hardwareÉ
;
Movea.l saveVidPtr(A3),A4 ; Point to vidParams.
Jsr CivicChangeHardware ; Reprogram Civic
Movem.l (Sp)+,D0-D1/A0/A4-A6 ; Restore the work register.
Rts
Endwith
CivicSetCompOut
;---------------------------------------------------------------------
;
; Sets/Clears the PRAM flag that tells primary init to boot off the composite
; out port when no monitor is detected on the DB15 port.
;
; A1 = Ptr to AuxDCE
; A2 = Ptr to cs parameter record
; A3 = Ptr to private storage
;
;
; Bit 0: if 0, set CompOutFlag, if 1, ClearCompOut.
;---------------------------------------------------------------------
WITH spBlock,CivicVidPrivates,SP_Params
;
; Set up a slot parameter block on the stack.
;
Move.w gFlags(A3),scratch(A3) ; save our flags
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 flag are in SP_FLAGS, which are in VendorUse5 byte.
;
SUBA #SizesPRAMRec,SP ; allocate block for pRAM record
MOVE.L SP,spResult(A0) ; point to it
_sReadPRAMRec ; read it
Bne CSetVinBadExit ; should not fail, but if so...
Move.b SP_Flags(SP),D0 ; Get the current flags
Move.b csMode(A2),D1 ; get boolean
Beq.s @SetFlag ; if 0, it means to set the flag
Bclr #spCompOut,D0 ; else, it means disable, so clear flag
Bra.s @WriteItOut ; and write it out
@SetFlag
Bset #spCompOut,D0 ; Set it, which means to enable
@WriteItOut
Move.b D0,SP_Flags(SP) ; write out the sp_flags byte
MOVE.L SP,spsPointer(A0) ; set up parameter block
_sPutPRAMRec ; write the new record out
Bne CSetVinBadExit ; any errors?
Adda #SizesPRAMRec+spBlockSize,SP ; Deallocate buffer and
Bra CivicCtlGood ; return good result.
CSetVinBadExit
Move.w scratch(a3),gflags(a3) ; Restore our gflags
Adda #SizesPRAMRec+spBlockSize,SP ; Deallocate buffer and
Bra CivicCtlBad ; return bad result.
CivicSwitchMode
;---------------------------------------------------------------------
;
; When driving a multiscan-capable display, this routine allows
; the various modes to swapped out both from a low-level software
; (i.e., Driver & Slot Manager) and hardware point of view.
;
; A1 = Ptr to AuxDCE
; A2 = Ptr to cs parameter record
; A3 = Ptr to private storage
;
;---------------------------------------------------------------------
With CivicVidPrivates,SpBlock,VDPageInfo
; Check to see if we even need to be here or notÉ
;
Cmpi.w #indexedSenseMSB1,saveMonID(A3) ; If weÕre not in the multiscan mode,
Bne CivicCtlBad ; then it's not safe to be here.
; Check to see if we can even do what was requestedÉ
;
Tst.w csPage(A2) ; If requested page is not zero,
Bne.s CivicCtlBad ; then we canÕt help Õem.
Move.l csData(A2),D2 ; Get the requested SpID.
Moveq #0,D0 ; Clear hi-half of mode/depth register.
Tst.w saveSizeVRAM(A3) ; Load the correct table depending on how much VRAM we have
Bne.s @2MegTable ; If 0, then 1 meg
Lea SwitchTable1Meg,A0 ; Point to the SwitchMode1Meg table.
Bra.s @ChkLoop ; start checking
@2MegTable Lea SwitchTable2Meg,A0 ; get the 2 meg table
@ChkLoop Move.b (A0)+,D1 ; If weÕre at the end of the table,
Beq CivicCtlBad ; then somethingÕs wrong.
Move.b (A0)+,D0 ; Get the max mode for this config.
Cmp.b D1,D2 ; If this is not the requested mode,
Bne.s @ChkLoop ; then keep looping.
; Make sure the new depth is okay for switchingÉ
;
Move.w csMode(A2),D1 ; Get the requested mode (depth).
Subi.w #FirstVidMode,D1 ; Make it indexed.
Subi.w #FirstVidMode,D0 ; Make the new max mode indexed.
Cmp.w D0,D1 ; If the current mode is > new max mode,
Bgt CivicCtlBad ; then punt.
Move.w D1,D0 ; Save the indexed mode.
; Switch to the new resolutionÉ
;
Cmp.b dCtlSlotID(A1),D2 ; If weÕre already in the requested resolution,
Beq CivicSetVidModeGuts ; then go try the depth switch.
Move.b D2,D1 ; Set up to do the resolution switch.
Bsr CivicSetResolution ; Switch to the new resolution.
Move.w D0,D1 ; Set up to do the depth switch.
Bra CivicSetVidModeGuts ; Switch to the new depth.
Endwith
CivicSetSync
;---------------------------------------------------------------------
;
; Enable (csMode = 0) or disable (csMode = 1) the DB15 Sync
;
; This routine will disable the sync lines going to the DB15 connector
; so that "green-aware" monitors can go into power-saving mode. If we
; are not driving an monitor out of that port, it will return an error.
;
; Note: It might be that in the future, there will be several levels of
; power-saving; Dropping CSYNC- will be one, HSYNC-, another, and
; both syncs another. Since Civic can only drop both, I will ignore
; a second undefined parameter.
;
; A1 = Ptr to AuxDCE
; A2 = Ptr to cs parameter record
; A3 = Ptr to private storage
;
;---------------------------------------------------------------------
WITH CivicVidPrivates
Move.w gFlags(A3),D0 ; get our flags
Btst #CompositeSyncOn,D0 ; are we driving out of Composite
Bne CivicCtlBad ; yes, then exit with bad mode
moveq #1,D0 ; Set up for CivicWrite
MOVE.b csMode(A2),D1 ; get the mode
Bne.s @WriteToSyncs ; To disable, write a 1 to CivicSyncEnable
Clr.l D0 ; else, write a 0 to enable
@WriteToSyncs
Move.l saveCivicBase(A3),A0 ; Get the Base Address for Civic
Move.l D0,Civic_SyncClr(A0) ; And disable or enable the sycns
BRA CivicStatGood ; => return no error
ENDWITH
**********************************************************************
*
* VideoClose releases the device's private storage and removes the
* interrupt handler.
*
*
* Entry: A0 = param block pointer
* A1 = AuxDCE pointer
*
* Other: A2 = temporary AuxDCE pointer copy
*
**********************************************************************
CivicVidClose
WITH CivicVidPrivates
MOVE.L dCtlStorage(A1),A3 ; A3 <- Ptr to private storage
MOVE.L (A3),A3 ;
BSR CivicDisableVGuts ; 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 saveVidPtr(A3),A0 ; Get pointer to video parameters block,
_DisposPtr ; and dispose of it.
Move.l save2ndVidPtr(A3),D0 ; Get pointer to video parameters block for RGB
Beq.s @DisposePrivate ; if nil, then don't need to dispose
_DisposPtr ; and dispose of it.
@DisposePrivate
MOVE.L dCtlStorage(A1),A0 ; dispose of the private storage
_DisposHandle ;
MOVEQ #noErr,D0 ; no error
RTS ; and return
ENDWITH
**********************************************************************
*
* Video Driver Status Call Handler. There are ten standard calls:
*
* ($00) Error
* ($01) Error
* ($02) GetMode
* ($03) GetEntries
* ($04) GetPage
* ($05) GetPageBase
* ($06) GetGray
* ($07) GetInterrupt
* ($08) GetGamma
* ($09) GetDefaultMode
* ($0A) ????
* ($0B) GetSyncs
*
* The following calls are Civic-specific:
*
* ($83) GetAltSense
* ($85) GetCompOut <LW14>
* ($87) GetRGBByPass
* ($88) GetVideoIn
* ($89) GetVidInMode
* ($8A) GetVidInRect
* ($8B) CivicGetCompCapabilities
*
* Entry: A0 = paramblock pointer
* A1 = AuxDCE pointer
* Uses: A2 = cs parameters
* A3 = pointer to private storage
* D0-D3 = scratch (don't need to be preserved)
*
* Exit: D0 = error code
*
**********************************************************************
CivicVidStatus
MOVEM.L A0/A1,-(SP) ; Save exit registers.
MOVE.L csParam(A0),A2 ; A2 <- Ptr to control parameters
MOVE.L dCtlStorage(A1),A3 ; A3 <- Ptr to private storage
MOVE.L (A3),A3 ;
MOVE.W csCode(A0),D0 ; get routine selector
Cmp.w #$80,D0 ; Is it a private control call
Bhs.s PrivateStatCall ; Go decode it
CMP.W #$0B,D0 ; IF csCode NOT IN [0..9] THEN
BHI.S CivicStatBad ; Error, csCode out of bounds.
MOVE.W CivicStatJumpTbl(PC,D0.W*2),D0 ;Get the relative offset to the routine.
JMP CivicStatJumpTbl(PC,D0.W) ;GOTO the proper routine.
CivicStatJumpTbl
DC.W CivicStatBad-CivicStatJumpTbl ; $00 => Error
DC.W CivicStatBad-CivicStatJumpTbl ; $01 => Error
DC.W CivicGetMode-CivicStatJumpTbl ; $02 => GetMode
DC.W CivicGetEntries-CivicStatJumpTbl ; $03 => GetEntries
DC.W CivicGetPage-CivicStatJumpTbl ; $04 => GetPage
DC.W CivicGetPageBase-CivicStatJumpTbl ; $05 => GetPageBase
DC.W CivicGetGray-CivicStatJumpTbl ; $06 => GetGray
DC.W CivicGetInterrupt-CivicStatJumpTbl ; $07 => GetInterrupt
DC.W CivicGetGamma-CivicStatJumpTbl ; $08 => GetGamma
DC.W CivicGetDefaultMode-CivicStatJumpTbl; $09 => GetDefaultMode
DC.W CivicStatBad-CivicStatJumpTbl ; $0A => Unused
DC.W CivicGetSyncs-CivicStatJumpTbl ; $0B => GetSyncs
PrivateStatCall
CMP.W #$8B,D0 ; IF csCode NOT IN [$80..$8B] THEN
BHI.S CivicStatBad ; Error, csCode out of bounds.
Subi.w #$80,D0 ; Normalize the code
MOVE.W PrivStatJumpTbl(PC,D0.W*2),D0 ; Get the relative offset to the routine.
JMP PrivStatJumpTbl(PC,D0.W) ; GOTO the proper routine.
PrivStatJumpTbl
DC.W CivicStatBad-PrivStatJumpTbl ; $80 => Unused
DC.W CivicStatBad-PrivStatJumpTbl ; $81 => Unused
DC.W CivicStatBad-PrivStatJumpTbl ; $82 => Unused
DC.W CivicGetAltSense-PrivStatJumpTbl ; $83 => CivicGetAltSense
DC.W CivicStatBad-PrivStatJumpTbl ; $84 => Unused (cscLowPower)
DC.W CivicGetCompOut-PrivStatJumpTbl ; $85 => CivicGetCompOut
DC.W CivicStatBad-PrivStatJumpTbl ; $86 => Unused
DC.W CivicGetRGBByPass-PrivStatJumpTbl ; $87 => CivicGetRGBByPass
DC.W CivicGetVideoIn-PrivStatJumpTbl ; $88 => GetVideoIn
DC.W CivicGetVidInMode-PrivStatJumpTbl ; $89 => GetVidInMode
DC.W CivicGetVidInRect-PrivStatJumpTbl ; $8A => GetVidInRect
DC.W CivicGetCompCapabilities-PrivStatJumpTbl ; $8B => CivicGetCompCapabilities
CivicStatBad MOVEQ #statusErr,D0 ; else say we don't do this one
BRA.S CivicStatDone ; and return
CivicStatGood MOVEQ #noErr,D0 ; return no error
CivicStatDone MOVEM.L (SP)+,A0/A1 ; Restore exit registers.
BRA CivicExitDrvr
CivicGetMode
;---------------------------------------------------------------------
;
; Return the current mode
;
; Inputs : A2 = pointer to csParams
; A3 = pointer to private storage
;
;---------------------------------------------------------------------
WITH CivicVidPrivates
MOVE.W saveMode(A3),csMode(A2) ; return the mode
Clr.w csPage(A2) ; return the page number (always 0)
Move.l saveBaseAddr(A3),csBaseAddr(A2) ; Return the screen baseAddr.
BRA.S CivicStatGood ; => return no error
ENDWITH
CivicGetEntries
;---------------------------------------------------------------------
;
; 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 : A1 = pointer to AuxDCE
; A2 = pointer to csParams/CLUT read register (not restored to csParams)
; A3 = pointer to private storage
;
;---------------------------------------------------------------------
With CivicCLUTRec
Movem.l D4-D7,-(Sp) ; Save work registers.
Tst.l -(Sp) ; Make some room.
Move.l csTable(A2),D0 ; If we were handed a nil pointer,
Beq @GEErr ; then hike.
Move.l D0,(Sp) ; Save the non-zero pointer.
Move.w saveMode(A3),D1 ; Get the current video mode.
Sub.w #FirstVidMode,D1 ; Convert it to an index.
Moveq #0,D3 ; clear all of D3 for .w compare.
Lea CivicCLUTTbl,A0 ; Point to the table of CLUT data.
Lea (A0,D1*CivicCLUTSize),A0 ; Point to the right entry.
Move.b ccRange(A0),D3 ; Get the CLUT range.
Move.w csCount(A2),D4 ; Get the number of entries to fill,
Bmi @GEErr ; and hike if itÕs out of range.
Cmp.w D3,D4 ; If D4-D3 > 0 (count > entries),
Bhi @GEErr ; then hike.
Move.w D4,D2 ; Otherwise, copy the count.
Move.b ccStart(A0),D4 ; Save the CLUT starting position.
Move.w ccSkip(A0),D5 ; Save the inter-entry skip factor.
Move.w D2,D6 ; Remember the csCount.
Move.l #colorSpecSize,D7 ; Save the size of each color spec entry
Move.w csStart(A2),D0 ; Get the start number to range check.
Addq.w #2,D0 ; If csStart < -2, then itÕs out of
Bmi @GEErr ; range.
Cmp.w #indexEntries,csStart(A2) ; If table accesses are to be indexed (csStart = -1),
Beq.s @GECom ; then go on.
Cmp.w #alphaEntries,csStart(A2) ; Do we have alpha entries (XColorSpec) (always indexed, csStart = -2)
Bne.s @CycleSeq ; then go on.
Move.l #xColorSpecSize,D7 ; Use D7 to contain the size of each entry
Bra.s @GECom ; and go on
@CycleSeq
Move.w D2,D1 ; Otherwise, sequence thru table from
Add.w csStart(A2),D2 ; csStart thru csCount entries.
; The following code is BAD, BAD, BAD! We should build our own table here so
; as to NOT mess up the userÕs data. But all the previous Apple video drivers
; have done the same thing here, so weÕll continue the trend for now.
Move.l (Sp),A0 ; Get ptr to csTable.
@TableLoop Move.w D2,value(A0,D1*colorSpecSize) ; Write the index into the table.
Subq #1,D2 ; Decrement index.
Dbra D1,@TableLoop ;
@GECom
Move.l (Sp)+,A0 ; Get/restore ptr to csTable.
Move.l saveVDACBase(A3),A2 ; Get ACDC base address.
Move.b SebastPCBR(A2),D0 ; Make sure we're writing to the Graphics CLUT
Bclr #fCivicVidInCLUT,D0 ; by zeroing the CLUT select bit in the PCBR
Move.b D0, SebastPCBR(A2) ; and write it back out.
Adda.w #SebastDataReg,A2 ; Add offset to Clut read register.
Move.w Sr,-(Sp) ; Save current interrupt level
Bsr CivicWaitVSync ; Wait for VBL (Preserves A0/D0).
@Repeat Move.w value(A0),D1 ; Get the NEXT Clut position into D1.
Cmp.w D3,D1 ; If this position is out of range,
Bhi.s @Until ; then go on.
Mulu.w D5,D1 ; Multiply index by skip value.
Add.b D4,D1 ; Add in the starting posistion.
Move.b D1,SebastAddrReg-SebastDataReg(A2) ; Tell the Clut where to read from.
Move.b (A2),D1 ; Get Red:
Move.b D1,rgb+red(A0) ; --> $rrXX
Move.b D1,rgb+red+1(A0) ; --> $rrrr
Move.b (A2),D1 ; Get Green:
Move.b D1,rgb+green(A0) ; --> $ggXX
Move.b D1,rgb+green+1(A0) ; --> $gggg
Move.b (A2),D1 ; Get Blue:
Move.b D1,rgb+blue(A0) ; --> $bbXX
Move.b D1,rgb+blue+1(A0) ; --> $bbbb
Cmp.l #xColorSpecSize,D7 ; Test for XColorSpec
Bne.s @DontReadAlpha ; if none then just skip alpha
Move.b (A2),D1 ; Get Alpha:
Move.b D1,xalpha(A0) ; --> $aaXX
Move.b D1,xalpha+1(A0) ; --> $aaaa
Bra.s @Until ; Go loop
@DontReadAlpha
Tst.b (A2) ; Skip Alpha.
@Until Add.l D7,A0 ; Point to next entry ColorTable.
Dbra D6,@Repeat
Move.w (Sp)+,Sr ; Restore previous interrupt level.
Movem.l (Sp)+,D4-D7 ; Restore work registers.
Bra CivicStatGood ; Return noError.
@GEErr Tst.l (Sp)+ ; Clean up stack.
Movem.l (Sp)+,D4-D7 ; Restore work registers.
Bra CivicStatBad ; Return statError.
CivicGetPage
;---------------------------------------------------------------------
;
; 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 CivicVidPrivates
MOVE csMode(A2),D1 ; get the mode
MOVE D1,D2 ; keep a copy
BSR CivicChkMode ; is this mode OK?
BNE CivicStatBad ; => not a valid mode
MOVE.W #1,csPage(A2) ; return page count
BRA CivicStatGood ; => return no error
ENDWITH
CivicGetPageBase
;---------------------------------------------------------------------
;
; Return the base address for the specified page in the current mode
;
;---------------------------------------------------------------------
WITH CivicVidPrivates
TST.W csPage(A2) ; are we returning page zero info?
BNE CivicStatBad ; only page 0 is valid
Move.l saveBaseAddr(A3),csBaseAddr(A2) ; Return the screen baseAddr.
BRA CivicStatGood ; => return no error
ENDWITH
CivicGetGray
;---------------------------------------------------------------------
;
; Return a boolean, set true if luminance mapping is on
;
;---------------------------------------------------------------------
WITH CivicVidPrivates
MOVEQ #0,D1 ; set up for BFEXTU
CivicGetFlagCom
BFEXTU GFlags(A3){D1:1},D0 ; get the state of flag
MOVE.B D0,csMode(A2) ; return value
BRA CivicStatGood ; => and return
ENDWITH
CivicGetInterrupt
;---------------------------------------------------------------------
;
; Return a boolean in csMode, set true if VBL interrupts are disabled
;
;---------------------------------------------------------------------
WITH CivicVidPrivates
MOVEQ #1,D1 ; set up BFEXTU to point at IntDisFlag
BRA.S CivicGetFlagCom ; and use common code
ENDWITH
CivicGetGamma
;---------------------------------------------------------------------
;
; Return the pointer to the current gamma table
;
;---------------------------------------------------------------------
WITH CivicVidPrivates
MOVE.L saveGammaPtr(A3),csGTable(A2) ; return the pointer to the structure
BRA CivicStatGood ; and return a good result
ENDWITH
CivicGetDefaultMode
;---------------------------------------------------------------------
;
; Read the card default mode from slot pRAM.
;
; A1 = Ptr to AuxDCE
; A2 = Ptr to cs parameter record
; A3 = Ptr to private storage
;
;---------------------------------------------------------------------
WITH spBlock,CivicVidPrivates,SP_Params
;
; 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. Built-in video 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 SP_LastConfig(SP),csMode(A2) ; return the result
ADDA #SizesPRAMRec+spBlockSize,SP ; release buffer
BRA CivicStatGood ;
ENDWITH
CivicGetVideoIn
;---------------------------------------------------------------------
;
; Return the status on whether video-in is enabled or not
;
; A1 = Ptr to AuxDCE
; A2 = Ptr to cs parameter record
; A3 = Ptr to private storage
;
; csMode: 0 = video-in is enabled
; 1 = video-in is disabled
;
;---------------------------------------------------------------------
WITH CivicVidPrivates
Btst #videoInEnb,GFlags(A3) ; Test our internal flags
Seq csMode(A2) ; If flag=0, video-in is disabled, so return true.
BRA CivicStatGood ;
ENDWITH
CivicGetVidInMode
;---------------------------------------------------------------------
;
; Return the VidIn Mode in the specified page, along with the video-in base address
;
; A1 = Ptr to AuxDCE
; A2 = Ptr to cs parameter record
; A3 = Ptr to private storage
;
;---------------------------------------------------------------------
WITH VDPageInfo
TST.W csPage(A2) ; are we returning page zero info?
BNE CivicStatBad ; only page 0 is valid
Move.l #vCivicVidInBase,csBaseAddr(A2) ; Return the video-in VRAM baseAddr.
Move.w saveVidInMode(A3),csMode(A2) ; Return the Video-In mode.
BRA CivicStatGood ; => return no error
ENDWITH
CivicGetVidInRect
;---------------------------------------------------------------------
;
; Return the VidInRect in the specified page, along with the video-in base address
;
; A1 = Ptr to AuxDCE
; A2 = Ptr to cs parameter record
; A3 = Ptr to private storage
;
;---------------------------------------------------------------------
WITH CivicVidPrivates, VDVidInRect
TST.W csPage(A2) ; are we returning page zero info?
BNE CivicStatBad ; only page 0 is valid
Move.l #vCivicVidInBase,csBaseAddr(A2) ; Return the video-in VRAM baseAddr.
Move.w currentTop(a3),(csRect+top)(A2) ; Return the top
Move.w currentLeft(a3),(csRect+left)(A2) ; Return the left
Move.w currentBottom(a3),(csRect+bottom)(A2) ; Return the bottom
Move.w currentRight(a3),(csRect+right)(A2) ; Return the right
BRA CivicStatGood ; => return no error
ENDWITH
CivicGetAltSense
;---------------------------------------------------------------------
;
; Returns the alternate senseID code thatÕs in use. It
; should be noted that we cannot disguish between PAL &
; NTSC monitors & encoder boxes once SetAltSense has
; been called (because both the monitor & box codes are
; mapped into the same indexedSense code).
;
;---------------------------------------------------------------------
With spBlock,CivicVidPrivates,SP_Params
;
; First, set up a slot parameter block on the stack.
;
Suba #spBlockSize,Sp ; Make a SpBlock on the stack.
Move.l Sp,A0 ; Get a pointer to it into A0.
Move.b dCtlSlot(A1),spSlot(A0) ; Set it up.
Clr.b spExtDev(A0)
;
; Next, read the current pRam so that we can determine whether the
; alternate senseID code is valid or not.
;
Suba #SizesPRAMRec,Sp ; Make an sPRAM block on the stack.
Move.l Sp,spResult(A0) ; Point to it.
_sReadPRamRec ; Get pRAM.
Clr.b csMode+1(A2) ; Assume the code already indexed for now.
Move.b SP_AltSense(Sp),D0 ; Get the alternate senseID byte.
Andi.b #spAltSenseValidMask,D0 ; If it is valid,
Bne.s @Valid ; return it.
Move.b #indexedNoConnect,csMode(A2) ; Otherwise, return the indexed no-connect code,
Bra.s @Exit ; and leave.
@Valid Move.b SP_AltSense(Sp),D0 ; Get the no-connect byte again.
Andi.b #spAltSenseMask,D0 ; Strip the validation code.
Cmp.b #indexedSenseVGA,D0 ; Is it the VGA code?
Bne.s @TryPal ; Nope, try PAL.
Move.b #extendedSenseVGA,D0
Bra.s @WriteExtended
@TryPal Cmp.b #indexedSensePAL,D0 ; Is it the PAL code?
Bne.s @TryGF ; Nope, try GoldFish.
Move.b #extendedSensePAL,D0
Bra.s @WriteExtended
@TryGF Cmp.b #indexedSenseGF,D0 ; Is it the GoldFish code?
Bne.s @Try19 ; Nope, try 19Ó.
Move.b #extendedSenseGF,D0
Bra.s @WriteExtended
@Try19 Cmp.b #indexedSense19,D0 ; Is it the 19Ó code?
Bne.s @TryRdRGB ; No, try the Radius ColorTPD.
Move.b #extendedSense19,D0
Bra.s @WriteExtended
@TryRdRGB Cmp.b #extended2PRdRGB,D0 ; Is it the ColorTPD.
Bne.s @TryRDMono ; Nope, try the Mono.
Bra.s @Write2PExtended
@TryRdMono Cmp.b #extended2PRdMono,D0 ; Is it the MonoTPD.
Bne.s @WriteIt ; Nope, assume indexed.
@Write2PExtended
Move.b #indexedSense2P,csMode+1(A2) ; Say code is type 3.
Bra.s @WriteIt
@WriteExtended Move.b #indexedNoConnect,csMode+1(A2) ; Say code is type 7.
@WriteIt Move.b D0,csMode(A2) ; Return valid monID.
@Exit Adda #SizesPRAMRec+spBlockSize,Sp ; Restore stack, and
Bra CivicStatGood ; go home.
Endwith
CivicGetRGBByPass
;---------------------------------------------------------------------
;
; Return the RGBBypass status in the csMode field
;
; A1 = Ptr to AuxDCE
; A2 = Ptr to cs parameter record
; A3 = Ptr to private storage
;
; The parameters are:
; csMode: (Byte): 0: If not driving out of composite, 1: if driving
; csStandard (Byte): 0: Driving PAL, 1: driving NTSC
; csConv (Byte): 0: Not using Apple Convolution, 1: Using Apple Convolution
;
;---------------------------------------------------------------------
WITH VDCompositeOut, CivicRecord
Move.w gFlags(A3),D0 ; Get our flags
Btst #CompositeSyncOn,D0 ; Look at whether we're driving composite
Beq.s @ClearMode ; If 0, then return bypass = 0
Move.b #1,csMode(A2) ; Else, return a 1
Bra.s @GetBypassType ; and exit
@ClearMode Clr.b csMode(A2) ; return 0
@GetBypassType Btst #NTSCTimingOn,D0 ; Look at the composite timing flag
Beq.s @SetPAL ; if 0, then it's PAL
Clr.b csStandard(A2) ; Clear the NTSC/PAL type
Bra.s @CheckConv ; check convolution
@SetPal Move.b #1,csStandard(A2) ; say it was PAL
@CheckConv Btst #ConvolutionON,D0 ; Look at the convolution flag
Beq.s @ClearConv ; if 0, then no convolution is going on
Move.b #1,csConv(A2) ; Set the convolution flag
Bra.s @theEnd ; exit
@ClearConv Clr.b csConv(A2) ; return with no convolution on
@theEnd BRA CivicStatGood ; => return no error
ENDWITH
CivicGetCompOut
;---------------------------------------------------------------------
;
; Read the cards composite out flag from the slot pRAM.
;
; A1 = Ptr to AuxDCE
; A2 = Ptr to cs parameter record
; A3 = Ptr to private storage
;
;---------------------------------------------------------------------
WITH spBlock,CivicVidPrivates,SP_Params
;
; 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. Built-in video 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 SP_Flags(SP),D0 ; Get the current flags
Btst #spCompOut,D0 ; Is composite out enabled
Beq @NoComposite ; no,
Move.b #0,csMode(A2) ; if it is, return the inverse (i.e. 0)
Bra.s @ExitCompOut
@NoComposite
Move.b #1,csMode(A2) ; Say we're not driving composite
@ExitCompOut
ADDA #SizesPRAMRec+spBlockSize,SP ; release buffer
BRA CivicStatGood ;
ENDWITH
CivicGetCompCapabilities
;---------------------------------------------------------------------
;
; Returns information on the capabilities of the current video mode
;
; A1 = Ptr to AuxDCE
; A2 = Ptr to cs parameter record
; A3 = Ptr to private storage
;
; The parameters are:
; csMode: (Byte) containing the spID of the mode we want info on
; (If 0, then use the current one)
;
; csNTSCID: (Byte): returns the spID for NTSC for the current amount of VRAM
; csNTSCIDConv: (Byte): returns the spID for NTSC Convolution
; csPALID: (Byte): returns the spID for PAL for the current amount of VRAM
; csPALIDConv: (Byte): returns the spID for PAL Convolution
;
;---------------------------------------------------------------------
WITH VDInternalInfo
Move.b csMode(A2),D1 ; Get the desired spID
Bne.s @GoodSPID ; If 0, then use the current one
Move.b saveSlotId(A3),D1 ; Get the current ID.
@GoodSPID
SUBA #spBlockSize,SP ; make a slot parameter block
MOVE.L SP,A0 ; get pointer to block in A0
Clr.b spSlot(A0) ; Look at slot 0
Clr.w spID(A0) ; Start looking at spID 0, no external devices.
Clr.b spTBMask(A0) ; Only look for the board sRsrc.
Move.w #catBoard,spCategory(A0) ; Look for: catBoard,
Move.w #typBoard,spCType(A0) ; typBoard,
Clr.w spDrvrSW(A0) ; 0,
Clr.w spDrvrHW(A0) ; 0.
Clr.l spParamData(A0) ; (The board sRsrc must be enabled.)
Bset #foneslot,spParamData+3(A0) ; Limit search to slot 0.
_GetTypeSRsrc ; Get the spsPointer.
Bne @BadVidInMax ; If an error, then bail out
MOVE.B #sVidParmDir,spID(A0) ; look for the video parameters dir
_sFindStruct ; Try to load it.
Bne @BadVidInMax ; If an error, then bail out
MOVE.B d1,spID(A0) ; look in the directory for this config's parameters
_sGetBlock ; Try to load it.
Bne @BadVidInMax ; If an error, then bail out
MOVE.L spResult(A0),A0 ; get pointer to it (dispose it later)
Move.l a0,-(sp) ; save it for later disposal
Tst.b saveSizeVRAM(A3) ; set up to return the correct spID's depending on VRAM
Bne.s @2Meg
Move.b cvpNTSCid1Meg(A0),csNTSCID(A2) ; return the equivalent NTSC Id
Move.b cvpPALid1Meg(A0),csPALID(A2) ; return the equivalent PAL Id
Bra.s @1
@2Meg
Move.b cvpNTSCid2Meg(A0),csNTSCID(A2) ; return the equivalent NTSC Id
Move.b cvpPALid2Meg(A0),csPALID(A2) ; return the equivalent PAL Id
@1
Move.b cvpConvNTSCid(A0),csNTSCIDConv(A2) ; return the equivalent id for NTSC Convolution
Move.b cvpConvPALid(A0),csPALIDConv(A2) ; return the equivalent id for NTSC Convolution
Clr.l D0 ; We will move amount of VRAM here
Move.b (A0),csMode(A2) ; Return the maxMode
Move.l (Sp)+,A0 ; Get the pointer to vidparams
_DisposPtr ; and dispose of it
ADDA #spBlockSize,SP ; release the spBlock
BRA CivicStatGood ; => return no error
@BadVidInMax
ADDA #spBlockSize,SP ; release the spBlock
BRA CivicStatBad ; => return error
ENDWITH
CivicGetSyncs
;---------------------------------------------------------------------
;
; Return a boolean, set true if RGB Syncs are OFF
; Clear the 2nd byte, saying we don't support levels of power-saving.
;
;---------------------------------------------------------------------
WITH CivicVidPrivates
Move.l saveCivicBase(A3),A0 ; Get the Base Address for Civic
Move.l Civic_SyncClr(A0),D0 ; Get the status of the enable bits
Andi.l #$1,D0 ; and look at bit 0
SEQ csMode(A2) ; if bit is 0, RGB Syncs are OFF, return true
Clr.b csMode+1(A2) ; and the next byte for good measure.
BRA CivicStatGood ; => and return
ENDWITH
;---------------------------------------------------------------------
;
; Exit from Control or Status.
;
; A0 = Ptr to param block.
; A1 = Ptr to AuxDCE.
; D0 = error code.
;
;---------------------------------------------------------------------
CivicExitDrvr BTST #NoQueueBit,ioTrap(A0) ; no queue bit set?
BEQ.S CivicGoIODone ; => no, not immediate
RTS ; otherwise, it was an immediate call
CivicGoIODone MOVE.L JIODone,-(Sp) ; Get the IODone address,
Rts ; and go there.
;---------------------------------------------------------------------
; Utils
;---------------------------------------------------------------------
;---------------------------------------------------------------------
;
; GetCivicReg
;
; This routine takes an offset into the CivicRegTable as input and
; returns the address and width of the corresponding
; Civic register.
;
; -> D0: The offset into the CivicRegTable of the desired Civic register.
; <- D1: The width (1 to 12 bits) of the Civic regiser/data.
; <- A0: Pointer to base address of the Civic register to write.
;
; Trashes D0-D1/A0.
With CivicFrame,CivicEntry,CivicRecord
dGetCivicReg
Lea dCivicRegTable,A0 ; Point to the CivicRegTable.
@GetCWidth Move.w width(A0,D0),D1 ; Get the register width
Move.w offset(A0,D0),D0 ; Get the register offset.
Move.l saveCivicBase(A3),A0 ; Point A0 at CivicÕs base address.
Adda.w D0,A0 ; Point to the desired register.
Rts
Endwith
;---------------------------------------------------------------------
;
; WriteCivic
;
; Civic registers are accessed 1 bit a time using D[0] of the processor
; bus. However, most of the registers are more than 1 bit wide.
; So, this routine takes as input the base address of the Civic
; register to write, the data to write out, and how wide the
; register/data is.
;
; Note: Civic Registers are ONLY accessible in 32-bit addressing
; mode.
;
; -> D0: The data to write out.
; -> D1: The width (1 to 12 bits) of the Civic regiser/data.
; -> A0: Pointer to base address of the Civic register to write.
;
; Trashes D0-D1/A0.
dWriteCivic
Subq #1,D1 ; Set up for Dbra loop.
@WriteABit Move.l D0,(A0)+ ; Write the current bit out.
Lsr.l #1,D0 ; Set up for next write.
Dbra D1,@WriteABit ; Loop until done.
Rts ; Return home.
;---------------------------------------------------------------------
;
; ReadCivic
;
; This routine complements the WriteCivic routine. It takes as
; input the Civic register to read and how wide the
; register is. It returns the registerÕs value.
;
; Note: Civic Registers are ONLY accessible in 32-bit addressing
; mode.
;
; <- D0: The Civic registerÕs data.
; -> D1: The width (1 to 12 bits) of the Civic regiser/data.
; -> A0: Pointer to base address of the Civic register to write.
;
; Trashes D1/A0.
dReadCivic
Move.l D2,-(Sp) ; Save our non-trashable work register.
Move.w D1,D0 ; Copy the register width.
Lsl.w #2,D0 ; Multiply it by four.
Adda.w D0,A0 ; Point to the last bit.
Subq #1,D1 ; Set up for Dbra loop.
Moveq #0,D0 ; Set up return value.
@ReadABit Lsl.w #1,D0 ; Set up for this read.
Move.l -(A0),D2 ; Get the current bit.
Bfins D2,D0{31,1} ; Save it.
Dbra D1,@ReadABit ; Loop until done.
Move.l (Sp)+,D2 ; Restore our work register.
Rts ; And return home.
;---------------------------------------------------------------------
;
; 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.
;
With CivicVidPrivates,CivicVidParams
CivicChkMode
Movem.l A0/D0,-(Sp) ; Save work registers.
Sub.w #FirstVidMode,D1 ; Make mode zero-based.
Blt.s @ModeBad ; If the passed-in mode is < 0,
; then punt.
Move.l saveVidPtr(A3),A0 ; Get a pointer to the video params.
Clr.l D0 ; We will move amount of VRAM here
Move.b cvpMaxGraphMode(A0),D0 ; Read the max value for this configuration.
Sub.w #FirstVidMode,D0 ; Make the max mode zero-based.
Cmp.w D0,D1 ; If the passed-in mode is > max mode,
Bgt.s @ModeBad ; then punt.
Cmp.w D1,D1 ; Set Eq when okay.
@ModeBad Movem.l (Sp)+,A0/D0 ; Restore work registers.
Rts
Endwith
;---------------------------------------------------------------------
;
; Wait for vertical blanking. Interrupts are set to level-2 in
; this routine.
;
; IMPORTANT! - This routine expects to be called in 32-bit addressing mode!!!!
;
; A3 = pointer to private storage
;---------------------------------------------------------------------
With CivicVidPrivates
CivicWaitVSync
MOVE.L A0,-(SP) ; Save work registers.
MOVE.L D0,-(SP) ; (Two MOVEs are faster than a MOVEM.)
MOVE.W SR,-(SP) ; Get the status register on stack.
MOVEQ #7,D0 ; Get mask into 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
Tst.w (Sp)+ ; Restore stack.
Move.l saveCivicBase(A3),A0 ; Point to the base of Civic.
Move.l #0,Civic_VBLClr(A0) ; Clear any pending interrupts.
Move.l #1,Civic_VBLClr(A0) ; Re-enable for NEXT interrupt.
@WaitForVBL Move.l Civic_VBLInt(A0),D0 ; Read the interrupt register.
Btst #0,D0 ; If a VBL has not occurred,
Beq.s @WaitForVBL ; then just spin.
@Done MOVE.L (SP)+,D0 ; Restore work registers.
MOVE.L (SP)+,A0 ; (Two MOVEs are faster than a MOVEM.)
RTS
Endwith
;---------------------------------------------------------------------
;
; SetDepth sets the depth in the DAC and the framebuffer.
;
; D1 contains the spID of the depth - $80 (the zero based mode ID)
; A1 = AuxDCE POINTER
; A2 = parameter block pointer
; A3 = dCtlStorage pointer
;
; scratch(A3).w: contains the previous mode
;
; Preserves all registers
;
;---------------------------------------------------------------------
With CivicVidPrivates,CivicVidParams,CivicBppParams,CivicRecord
CivicSetDepth
Movem.l A0-A1/D0-D2,-(Sp) ; Save our work registers.
; Set up for this routineÉ.
Move.l saveVidPtr(A3),A1 ; Get a pointer to the vidParams.
Adda.w #CVPHdrSize,A1 ; Skip past the header info.
Move.w #CBPSize,D0 ; Get the size of each bpp entry.
Mulu D1,D0 ; Multiply it by the right entry.
Adda.l D0,A1 ; Skip to the entry we want.
; Update our videoIn GFlag
Tst.w cbpBusSize(A1) ; If it's 0, video-in is enabled
Beq @SetDepthVin ;
Bclr #videoInEnb,GFlags(A3) ; say it's disabled
; Calculate the baseAddress to put into Civic
Move.l saveBaseAddr(A3),D2 ; Get our BaseAddress
Lsr.l #5,D2 ; Normalize it for Civic
Andi.l #$FF,D2 ; Only 8 bits are valid
; Get the current state of important video-in parameters
dRead_Civic #VDCClk,D1 ; Get the state of the VDC clock
Move.w D1,VDCCLkState(A3) ; and save it
dRead_Civic #VDCEnb,D1 ; Get the state of the VDC enable bit
Move.w D1,VDCEnbState(A3) ; and save it
Clr.w OverlayState(A3) ; Assume it's off
Move.l saveVDACBase(A3),A0 ; Get a pointer to the CLUT/DAC.
Move.b SebastPCBR(A0),D0 ; and get the value
Btst #fCivicVidInOvly,D0 ; Check the Overlay bit
beq.s @NoChange ; already off
Move.w #1,OverlayState(A3) ; say it's on.
@NoChange
dWrite_Civic #0,#VDCEnb ; Disable VDC interrupts.
dWrite_Civic #1,#VDCClk ; Disable VDC clock.
; Wait for the next VBL before trying to switch depths.
;
Move.w Sr,-(Sp) ; Save the current interrupt level.
Bsr.s CivicWaitVSync ; Wait for the next VBL.
dWrite_Civic #0,#Enable ; Disable Casio (the timing generator).
; Switch the framebufferÕs depth.
;
dWrite_Civic cbpBusSize(A1),#BusSize ; Write the BusSize parameter
dWrite_Civic cbpHSerr(A1),#HSerr ; Write out the horizontal timing parameters.
dWrite_Civic cbpHlfLn(A1),#HlfLn ;
dWrite_Civic cbpHEq(A1),#HEq ;
dWrite_Civic cbpHSP(A1),#HSP ;
dWrite_Civic cbpHBWay(A1),#HBWay ;
dWrite_Civic cbpHAL(A1),#HAL ;
dWrite_Civic cbpHFP(A1),#HFP ;
dWrite_Civic cbpHPix(A1),#HPix ;
dWrite_Civic #$FF0,#VInHal ; Since video-in is not enabled
dWrite_Civic #$000,#VInHFPD ; Set the video-in parameters
dWrite_Civic #$FF8,#VInHFP ; Éway into the blanking period.
dWrite_Civic #$FF0,#VInVal ;
dWrite_Civic #$FF8,#VInVFP ;
dWrite_Civic cbpGSCDivide(A1),#GSCDivide ; Set the framebuffer params for this depth.
dWrite_Civic cbpRowWords(A1),#RowWords ;
dWrite_Civic D2,#BaseAddr ;
dWrite_Civic cbpAdjF1(A1),#AdjF1 ;
dWrite_Civic cbpAdjF2(A1),#AdjF2 ;
dWrite_Civic cbpPipeD(A1),#PipeD ;
; Switch the CLUT/DACÕs depth.
;
Move.l saveVDACBase(A3),A0 ; Get a pointer to the CLUT/DAC.
Move.w cbpSebastPCBR(A1),D0 ; Get the PCBR value (Overlay is disabled in sresource).
Move.b D0,SebastPCBR(A0) ; Change the depth.
; Now, reset the timing generator.
;
dWrite_Civic #1,#Enable ; Enable Casio (the timing generator).
Move.l saveCivicBase(A3),A0 ; Point to the base of Civic.
Jsr CivicReset ; Reset Civic (Needs A3 = vidprivates, trashes A0)
Move.w (Sp)+,Sr ; Restore the interrupt level.
@SetDepthFinishUp
Movem.l (Sp)+,A0-A1/D0-D2 ; Restore the work registers.
Rts ; Return to caller.
@SetDepthVin
Bset #videoInEnb,GFlags(A3) ; Say video-in is enabled
Movem.l A3-A5/D2-D7,-(Sp) ; Save our registers
Move.l saveVidPtr(A3),A4 ; A pointer to our VidParams
Move.l saveVDACBase(A3),A5 ; Get a pointer to the CLUT Base
Move.b SebastPCBR(A5),D7 ; and get the value of the CLUT
Andi.b #$80,D7 ; Clear all but the Overlay bit
Or.b D1,D7 ; or in D1 (contains the zero-based graphics mode)
Bset #fCivicVidInEnb,D7 ; Tell Sebastian we have video-in enabled
Cmp.w #16,saveVidInMode(A3) ; Is our video-in in 16bpp
Bne.s @SetVidInBpp ; no, don't set that bit
Bset #fCivicVidInBpp,D7 ; Tell Sebastain we have 16bpp video-in
@SetVidInBpp
Jsr CSetVidInModeGuts ; Program Civic when video-in is enabled
Move.l saveVDACBase(A3),A5 ; Get a pointer to the CLUT Base
Move.b D7,SebastPCBR(A5) ; Change the CLUT.
Move.w D7,-(SP) ; Save it accross SetVidRect
; Now resize the vid in rect
Move.l saveVidPtr(A3),A4 ; A pointer to our VidParams
Move.w currentRight(a3),-(SP) ; Get the current video in rect
Move.w currentBottom(a3),-(SP) ;
Move.w currentLeft(a3),-(SP) ;
Move.w currentTop(a3),-(SP) ; in reverse order
Jsr CivicSetVidRectJSR ; Go do the work
Adda #8,SP ; Clean up the stack
Move.w (SP)+,D7 ; Get our PCB value back
; If our previous mode was the "threshold" mode (where video-in was disabled) then the
; State registers are valid. Otherwise, they are not (since we can just be changing from one
; video-in capable mode to another.
Move.w saveNewBaseMode(A3),D0 ; Get the threshold mode
Cmp.w scratch(A3),D0 ; Was our old mode the "threshold" byte
Bne.s @DontChange ; If not, then don't write the saved state
Tst.w OverlayState(A3) ; Was the overlay enable bit on before the switch?
Beq.s @NoOverlay ; nope, then don't do it
Bset #fCivicVidInOvly,D7 ; else, enable the Overlay bit
Move.l saveVDACBase(A3),A5 ; Get a pointer to the CLUT Base
Move.b D7,SebastPCBR(A5) ; Change the CLUT.
@NoOverlay
Move.w VDCEnbState(A3),D2 ; Get it from our privates <LW16>
dWrite_Civic D2,#VDCEnb ; Restore VDC interrupt state. <LW16>
Move.w VDCClkState(A3),D2 ; Get it from our privates <LW16>
dWrite_Civic D2,#VDCClk ; Restore VDC clock state. <LW16>
@DontChange
Movem.l (Sp)+,A3-A5/D2-D7 ; Restore our registers
Bra @SetDepthFinishUp
Endwith
;---------------------------------------------------------------------
;
; 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 CivicVidPrivates,CivicVidParams,CivicBppParams
CivicGrayScreen
Movem.l D0-D5/A1-A2,-(Sp) ; Save our work registers.
Move.l saveBaseAddr(A3),A2 ; Get the base address of the screen.
@GetParms Move.l saveVidPtr(A3),A1 ; Get a pointer to the vidParams.
Move.w cvpNumRows(A1),D4 ; Get the number of rows to gray.
Move.b cvpScanCtl(A1),D2 ; Flag whether weÕre interlaced or not.
Adda.w #CVPHdrSize,A1 ; Skip past the header info.
Move.w #CBPSize,D0 ; Get the size of each bpp entry.
Mulu D1,D0 ; Multiply it by the right entry.
Adda.l D0,A1 ; Skip to the entry we want.
Move.w cbpRowWords(A1),D3 ; Get the number of longwords/row.
Tst.b D2 ; If weÕre on an interlaced display
Bne.s @Interlace ; then adjust accordingly.
Lsl.w #3,D3 ; Normalize for progressive displays.
Bra.s @SizeIt ; (Skip interlace here.)
@Interlace Lsl.w #2,D3 ; Normalize for interlaced displays.
@SizeIt Cmp.b #SixthVidMode-FirstVidMode,D1 ; If weÕre not doing 32bpp,
Bne.s @DbraAdj ; then just go on.
Lsr.w #1,D3 ; 32bpp uses double longs.
@DbraAdj Subq #1,D3 ; Set up for Dbra loop.
Lea CivicPats,A1 ; Point to the table of gray patterns.
Move.l (A1,D1*4),D2 ; Get the gray pattern.
@NxtRow Move.w D3,D5 ; Get the number of longswords/row.
@NxtLong Move.l D2,(A2)+ ; Write out gray to the frame bufferÉ
Cmp.b #SixthVidMode-FirstVidMode,D1 ; If weÕre not doing 32bpp,
Bne.s @Skip32bpp ; then just go on.
Not.l D2 ; Invert for next pixel.
Move.l D2,(A2)+ ; Write it out.
Not.l D2 ; Invert for next pixel.
@Skip32bpp Dbra D5,@NxtLong ; Loop until done
Not.l D2 ; Invert the pattern for the next row.
Dbra D4,@NxtRow ; Repeat for each row.
Movem.l (Sp)+,D0-D5/A1-A2 ; Restore the work registers.
Rts ; Return to caller.
Endwith
;---------------------------------------------------------------------
;
; 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 CivicVidPrivates,CivicVidParams,CivicBppParams
CivicBlackScreen
Movem.l D0-D5/A1-A2,-(Sp) ; Save our work registers.
Move.l saveBaseAddr(A3),A2 ; Get the base address of the screen.
@GetParms Move.l saveVidPtr(A3),A1 ; Get a pointer to the vidParams.
Move.w cvpNumRows(A1),D4 ; Get the number of rows to gray.
Move.b cvpScanCtl(A1),D2 ; Flag whether weÕre interlaced or not.
Adda.w #CVPHdrSize,A1 ; Skip past the header info.
Move.w #CBPSize,D0 ; Get the size of each bpp entry.
Mulu D1,D0 ; Multiply it by the right entry.
Adda.l D0,A1 ; Skip to the entry we want.
Move.w cbpRowWords(A1),D3 ; Get the number of longwords/row.
Tst.b D2 ; If weÕre on an interlaced display
Bne.s @Interlace ; then adjust accordingly.
Lsl.w #3,D3 ; Normalize for progressive displays.
Bra.s @SizeIt ; (Skip interlace here.)
@Interlace Lsl.w #2,D3 ; Normalize for interlaced displays.
@SizeIt Cmp.b #SixthVidMode-FirstVidMode,D1 ; If weÕre not doing 32bpp,
Bne.s @DbraAdj ; then just go on.
Lsr.w #1,D3 ; 32bpp uses double longs.
@DbraAdj Subq #1,D3 ; Set up for Dbra loop.
Move.l #$FFFFFFFF,D2 ; Set the black pattern.
@NxtRow Move.w D3,D5 ; Get the number of longswords/row.
@NxtLong Move.l D2,(A2)+ ; Write out gray to the frame bufferÉ
Cmp.b #SixthVidMode-FirstVidMode,D1 ; If weÕre not doing 32bpp,
Bne.s @Skip32bpp ; then just go on.
Not.l D2 ; Invert for next pixel.
Move.l D2,(A2)+ ; Write it out.
Not.l D2 ; Invert for next pixel.
@Skip32bpp Dbra D5,@NxtLong ; Loop until done
; Not.l D2 ; Invert the pattern for the next row.
Dbra D4,@NxtRow ; Repeat for each row.
Movem.l (Sp)+,D0-D5/A1-A2 ; Restore the work registers.
Rts ; Return to caller.
Endwith
;---------------------------------------------------------------------
;
; Trans5to8
;
; <-> D1: 5-bit value to be converted into an 8-bit index.
;
CivicTrans5to8
Move.l D0,-(Sp) ; Save D0 as scratch.
Moveq #0,D0 ; Clear it.
Move.w D1,D0 ; D1 = ---43210, D0 = ---43210.
Lsl.w #3,D1 ; D1 = 43210---, D0 = ---43210.
Lsr.w #2,D0 ; D1 = 43210---, D0 = -----432.
Or.w D0,D1 ; D1 = 43210432.
Move.l (Sp)+,D0 ; Restore D0.
Rts
;---------------------------------------------------------------------
;
; DirectCLUTSet writes gamma-corrected ascending grayscale-like ramps
; into the CLUT
;
; A3 = dCtlStorage pointer
;
; Preserves all registers used.
;
;---------------------------------------------------------------------
With CivicVidPrivates
CivicDirectCLUTSet
MOVEM.L D0-D7/A0/A4-A6,-(SP) ; save registers
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.W #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
ADDQ #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
ADDA D1,A6 ; calc baseÉ
ADDA D1,A6 ; Éof blue
@OneTbl MOVE.W gDataCnt(A0),D2 ; Get number of entries.
Subq #1,D2 ; Make it zero based.
MOVE.L saveVDACBase(A3),A0 ; point to the hardware
Move.b SebastPCBR(A0),D0 ; Make sure we're writing to the Graphics CLUT
Bclr #fCivicVidInCLUT,D0 ; by zeroing the CLUT select bit in the PCBR
Move.b D0, SebastPCBR(A0) ; and write it back out.
ADDA #SebastDataReg,A0 ; point to data register
Clr.b SebastAddrReg-SebastDataReg(A0) ; start at the beginning of CLUT
Move.w GFlags(A3),D5 ; Get the flags for quick access.
Move.w saveMode(A3),D1 ; Get the current mode.
Cmp.b #FifthVidMode,D1 ; If weÕre not doing 16bpp,
Bne.s @32bpp ; then go on.
Bset #UseTrans,D5 ; Remember to do 5-to-8 bit translation stuff.
Move.w #$1F,D2 ; There are only 32 entries to whack in 16bpp mode.
@32bpp MOVE.W SR,-(SP) ; preserve the status register
BSR CivicWaitVSync ; wait for next blanking period (preserves A0)
; Write an incrementing grayscale ramp.
Moveq #0,D0 ; Start the ramp at zero.
Btst #videoInEnb,D5 ; If video-in is enabled, need to read the alpha
Bne @VidRepeat ; before writing the grey
@Repeat Move.w D0,D1 ; Copy the current index.
Btst #UseTrans,D5 ; If we donÕt need to translate this value,
Beq.s @Index ; then just go on.
Bsr.s CivicTrans5to8 ; Otherwise, convert it, and use it
@Index MOVE.B (A4,D1),(A0) ; Write gamma-corrected red.
MOVE.B (A5,D1),(A0) ; Write gamma-corrected green
MOVE.B (A6,D1),(A0) ; Write gamma-corrected blue.
Clr.b (A0) ; Skip alpha.
Addq #1,D0 ; Increment the ramp index.
DBRA D2,@Repeat ; Loop until done.
Bra.s @FinishDGray ; Finish it off
@VidRepeat Move.w D0,D1 ; Copy the current index.
Btst #UseTrans,D5 ; If we donÕt need to translate this value,
Beq.s @VidIndex ; then just go on.
Bsr.s CivicTrans5to8 ; Otherwise, convert it, and use it
@VidIndex
Move.b (A0),D7 ; Read: red,
Move.b (A0),D7 ; green,
Move.b (A0),D7 ; blue,
Move.b (A0),D7 ; alpha,
Move.b D0,SebastAddrReg-SebastDataReg(A0) ; ReWrite the CLUT Address register
MOVE.B (A4,D1),(A0) ; Write gamma-corrected red.
MOVE.B (A5,D1),(A0) ; Write gamma-corrected green
MOVE.B (A6,D1),(A0) ; Write gamma-corrected blue.
Move.b D7,(A0) ; Write save alpha.
Addq #1,D0 ; Increment the ramp index.
DBRA D2,@VidRepeat ; Loop until done.
@FinishDGray
MOVE.W (SP)+,SR ; restore the status reg
MOVEM.L (SP)+,D0-D7/A0/A4-A6 ; restore saved registers
RTS
Endwith
;---------------------------------------------------------------------
;
; VideoCLUTSet writes gamma-corrected ascending grayscale-like ramps
; into the VideoCLUT
;
; A3 = dCtlStorage pointer
;
; Preserves all registers used.
;
;---------------------------------------------------------------------
With CivicVidPrivates
CivicVideoCLUTSet
MOVEM.L D0-D7/A0/A4-A6,-(SP) ; save registers
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.W #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
ADDQ #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
ADDA D1,A6 ; calc baseÉ
ADDA D1,A6 ; Éof blue
@OneTbl MOVE.W gDataCnt(A0),D2 ; Get number of entries.
Subq #1,D2 ; Make it zero based.
MOVE.L saveVDACBase(A3),A0 ; point to the hardware
Move.b SebastPCBR(A0),D0 ; Make sure we're writing to the Video CLUT
Bset #fCivicVidInCLUT,D0 ; by zeroing the CLUT select bit in the PCBR
Move.b D0, SebastPCBR(A0) ; and setting it back out.
Move.b D0,D5 ; Save the CLUT settings for quick access later.
ADDA #SebastDataReg,A0 ; point to data register
Clr.b SebastAddrReg-SebastDataReg(A0) ; start at the beginning of CLUT
Move.w #$1F,D2 ; There are only 32 entries to whack in 16bpp mode.
@32bpp MOVE.W SR,-(SP) ; preserve the status register
BSR CivicWaitVSync ; wait for next blanking period (preserves A0)
; Write an incrementing grayscale ramp.
Moveq #0,D0 ; Start the ramp at zero.
@Repeat Move.w D0,D1 ; Copy the current index.
Btst #fCivicVidInBpp,D5 ; Is the video-in in Grey scale
Bne.s @Color ; no, then just write the value
Moveq #31,D1 ; Need to invert the table
Sub.w D0,D1 ; so start at the top
@Color
lsl.w #3,D1 ; and shift it to the most significant 5 bits
@Index MOVE.B (A4,D1),(A0) ; Write gamma-corrected red.
MOVE.B (A5,D1),(A0) ; Write gamma-corrected green
MOVE.B (A6,D1),(A0) ; Write gamma-corrected blue.
Addq #1,D0 ; Increment the ramp index.
DBRA D2,@Repeat ; Loop until done.
@FinishDGray
MOVE.W (SP)+,SR ; restore the status reg
MOVEM.L (SP)+,D0-D7/A0/A4-A6 ; restore saved registers
RTS
Endwith
;---------------------------------------------------------------------
;
; This routine is used to program the VidIn Horiz and Vert values, depending
; on the rect that is in the stack.
;
; A3 = Pointer to CivicVidPrivates Table
; A4 = Pointer to VidParams
; A5 = Pointer to VDACBase
;
; Uses A6 (preserved)
; D0,D1,D2,D3,D4,D6,D7 (not preserved)
;
;
;---------------------------------------------------------------------
CivicSetVidRectJSR
; Adjust the stack pointer so our parameters our available
Move.l A6,-(Sp) ; save A6's value
Move.l Sp,A6 ; Get a pointer to it
Adda.l #8,A6 ; our local variables
; If all the parameters are 0, then set the vidRect way out in right field: (This will happen if
; video-in has never been enabled)
Move.w bottom(A6),D0 ; Gets the bottom (2-bytes) of the csRect
Add.w top(A6),D0 ; Gets the top (2-bytes) of the csRect
Add.w left(A6),D0 ; Gets the left of the csRect
Add.w right(A6),D0 ; Gets the right of the csRect
Bne.s @NotAZeroRect ; It's not a nil rect
dRead_Civic #VFP,D6 ; Saves actual HAL into D6
dRead_Civic #HFP,D7 ; Saves actual HFP into D7
Addi.w #2,D7 ;
Move.w D7,saveVinHAL(a3) ; Set the video-in paramsÉ
Addi.w #2,D7 ;
Move.w D7,saveVinHFP(a3) ;
Move.w #$0,saveVinHFPD(a3) ;
Addi.w #2,D6 ;
Move.w D6,saveVinVAL(a3) ;
Addi.w #2,D6 ;
Move.w D6,saveVinVFP(a3) ;
Clr.w saveVidInSize(a3) ; 0 = "small video"
Bra WriteVidInParms
@NotAZeroRect
; We have a valid rect and page. Set the VidInSize to 0 -- will set to 1 if necessary later
dRead_Civic #HAL,D6 ; Saves actual HAL into D6
dRead_Civic #HFP,D7 ; Saves actual HFP into D7
Clr.w saveVidInSize(a3) ; 0 = "small video"
; Now, calculate the vertical parameters
;
; If we are in progressive mode the values for VinVAL and VinVFP are given by:
;
; VinVAL = VAL + (csRect.top << 1)
; VinVFP = VAL + (csRect.bottom << 1)
;
Move.w cvpVAL(A4), D1 ; Save VAL so we don't have to get it from memory repeatedly
Tst.b cvpScanCtl(A4) ; ScanCtl inverted when you read it back, but here it is the value programmed
; into Civic: 0 = progressive mode, 1 = interlaced
Bne.s VidInVertInter ; Do the interlaced mode
Move.w top(A6),D0 ; Gets the top (2-bytes) of the csRect
Lsl.w #1,D0 ; Multiply by two (if carry set the rect is too big. Check for this?)
Add.w D1,D0 ; and add VAL to it
Move.w D0, saveVinVAL(a3) ; Save VinVAL to dump it to civic later
Move.w bottom(A6),D0 ; Gets the bottom (2-bytes) of the csRect
Lsl.w #1,D0 ; Multiply by two (if carry set, there should've been an error
Add.w D1,D0 ; and add VAL to it
Move.w D0, saveVinVFP(a3) ; Save VinVFP to dump it to civic later
Bra.s VidInHoriz ; Go do the horizontal parameters
VidInVertInter
;
; If we are in interlaced mode, we have to adjust the parameters to the fact that each field contains only half
; the number of lines that it does in interlace mode, thus:
;
; VinVAL = VAL + csRect.top
; VinVFP = VAL + csRect.bottom
;
; VAL is in D1
;
Move.w top(A6),D0 ; Gets the top (2-bytes) of the csRect
Add.w D1,D0 ; Add the top edge to VAL
Bclr #0,D0 ; Make sure VinVAL is even
Move.w D0, saveVinVAL(a3) ; Save VinVAL to dump it to civic later
Move.w bottom(A6),D0 ; Get the left point of the csRect
Add.w D1,D0 ; Add the adjusted VAL to it
Bclr #0,D0 ; Make sure VinVFP is also even (or Interlaced Mode)
Move.w D0, saveVinVFP(a3) ; Save VinVFP to dump it to civic later
VidInHoriz
; Now, we are ready to do the horizontal parameters. This is more complicated because the VidParams for the horizontal
; values change depending on the bit depth
;
; These values will depend on whether we are in 8bpp/16bpp video-in and the graphics bpp:
;
; For 16bpp Video-in (any graphics bpp) OR 8bpp video-in with 16bpp graphics:
;
; VinHAL = HAL + csRect.left
; VinHFP = HFP + csRect.right
;
; For 8bpp Video-in AND 1,2,4,8bpp graphics
;
; VinHAL = HAL + (csRect.left >> 1) - 1
; VinHFP = HFP + (CsRect.left >> 1) - 1
;
; VinHFPD = 0 always.
;
Clr.w saveVinHFPD(a3) ; VinVFPD is always zero
Move.b SebastPCBR(A5), D0 ; Get the PCBR Value
Btst #fCivicVidInBpp,D0 ; Check to see what bpp video-in we have
Bne.s VidInHoriz16bpp ; ( 1 = 16bpp)
; we're in 8bpp video-in here
Andi.b #mCivicGrBpp,D0 ; Look at the graphics bpp (#mCivicGrBpp = $07);
Cmp.b #vCivicGr16Bpp,D0 ; Is it 16bpp graphics (8bpp video)
Beq.s VideoIsSmall ; We're in 8bpp video-in, so saveVidInSize should always <LW14>
; be 0 <LW14>
; OK, now only in 8bpp video-in, 1,2,4,8 graphics (HAL in D6)
; First check to see if we have to set the "big/small" video bit
;
Move.w (right)(A6),D2 ; Gets the right of the csRect
Sub.w (left)(A6),D2 ; we have the width * 2
Lsr.w #1,D2 ; Divide by 2 to get the width
Cmpi.w #496,D2 ; the max size for a small video <LW14>
Ble.s VideoIs8bppSmall ; no need to set this VidInSize bit
Move.w #1,saveVidInSize(a3) ; each scan line is written into 1.5 lines of VRAM
VideoIs8bppSmall
Move.w (left)(A6),D2 ; Gets the left of the csRect
Lsr.w #1,D2 ; Divide it by 2
Add.w D6,D2 ; Add HAL to it
Subi.w #1,D2 ; and subtract the fudge factor
Move.w D2,saveVinHAL(a3) ; Save it in our privates
Move.w (right)(A6),D2 ; Gets the right of the csRect
Lsr.w #1,D2 ; Divide it by 2
Add.w D6,D2 ; Add HAL to it
Subi.w #1,D2 ; and subtract the fudge factor
Move.w D2,saveVinHFP(a3) ; Save it in our privates
Moveq #0,D4 ; Flag for use in CkClipping: 0: csRect parameters need to be halved
Bra.s CkHorizClipping ; Make sure video-in rect fit in screen
; we're in 16bpp video-in here (HAL in D1)
VidInHoriz16bpp
; First check to see if we have to set the "big/small" video bit
;
Move.w (right)(A6),D2 ; Gets the right of the csRect
Sub.w (left)(A6),D2 ; we have the width
Cmpi.w #496,D2 ; the max size for a small video <LW14>
Ble.s VideoIsSmall ; no need to set this VidInSize bit
Move.w #1,saveVidInSize(a3) ; each scan line is written into 1.5 lines of VRAM
VideoIsSmall
Move.w (left)(A6),D2 ; Gets the left of the csRect
Add.w D6,D2 ; Add HAL to it
Subi.w #1,D2 ; and subtract the fudge factor
Move.w D2,saveVinHAL(a3) ; Save it in our privates
Move.w (right)(A6),D2 ; Gets the right of the csRect
Add.w D6,D2 ; Add HAL to it
Subi.w #1,D2 ; and subtract the fudge factor
Move.w D2,saveVinHFP(a3) ; Save it in our privates
Moveq #1,D4 ; Flag for use in CkClipping: 1: csRect parameters do not need to be halved
CkHorizClipping
;
; Horizontal Clipping will occur if VinHFP > HFP. In that case, we need to return in the csRect the
; maximum value for csRect.right:
;
; csRect.right = csRect.left + ( D4 == 0 ? (HFP - VinHAL)*2 : (HFP - VinHAL) )
; D4 contains a flag that will tell me (if 0) that the VinHAL needs to be doubled to arrive at the correct screen coordinates
;
; Vertical Clipping will occur if VinVFP > VFP. Again, we need to return the maximum vlaue for csRect.bottom
;
; csRect.bottom = csRect.top + ( Interlaced ? (VFP - vinVFP) : (VFP - VinVFP) / 2
;
; depending on whether we're in interlaced or not
; VinHFP is in D2
Clr.w D3 ; Flag to show that clipping occurred
Cmp.w D7,D2 ; Need to clip Horizontally if VinHFP
Bgt DoHorizClipping ; is greater than HFP (Set D3 to 1 if clipped occurred)
CkVertClipping
Move.w cvpVFP(A4),D0 ; Get the graphics vert front porch
Move.w saveVinVFP(a3),D2 ; Get the video-in vert front porch
Cmp.w D0,D2 ; Need to clip Horizontally if VinHFP
Bgt DoVertClipping ; is greater than HFP (Set D3 to 1 if clipped occurred)
Bra.s TestClipping ; do the vertical checking
DoHorizClipping
; Horizontal Clipping will occur if VinHFP > HFP. In that case, we need to return in the csRect the
; maximum value for csRect.right:
;
; csRect.right = csRect.left + ( D4 == 0 ? (HFP - VinHAL)*2 : (HFP - VinHAL) )
; D4 contains a flag that will tell me (if 0) that the VinHAL needs to be doubled to arrive at the correct screen coordinates
Moveq #1, D3 ; set "Clipped" Flag
Move.w D7,D1 ; get HFP
Sub.w saveVinHAL(a3),D1 ; subtract VinHAL from it
Tst.b D4 ; do we need to double the value (D4 has the "need to double flag for horiz values")
Bne.s ExitHorizClipping ; nope
Lsl.w #1, D1 ; we double the value
ExitHorizClipping
Add.w (left)(A6), D1 ; write the max right to csRect
Move.w D1,(right)(A6) ;
Bra.s CkVertClipping ; do the vertical checking
DoVertClipping
; Vertical Clipping will occur if VinVFP > VFP. Again, we need to return the maximum vlaue for csRect.bottom
;
; csRect.bottom = csRect.top + ( Interlaced ? (VFP - vinVFP) : (VFP - VinVFP) / 2
;
; depending on whether we're in interlaced or not
Moveq #1, D3 ; set "Clipped" Flag
Move.w cvpVFP(A4),D1 ; get VFP
Sub.w saveVinVAL(a3),D1 ; subtract VinVAL from it
Tst.b cvpScanCtl(A4) ; do we need to half the value (cvpScanCtl = 1 for interlaced)
Bne.s ExitVertClipping ; nope
Lsr.w #1, D1 ; we half the value for progressive
ExitVertClipping
Add.w (top)(A6), D1 ; write the max bottom to csRect
Move.w D1,(bottom)(A6) ;
TestClipping
Tst.b D3 ; Any Clipping?
Bne CRectGotClipped ; yes, return an error (csRect was already written with the write value in the Do..Clipping routines
; prepare to write the VidIn parameters (We're still in 32-bit mode)
WriteVidInParms
; Wait for the next VBL before trying to write to Civic.
;
Move.w Sr,-(Sp) ; Save the current interrupt level.
Bsr CivicWaitVSync ; Wait for the next VBL.
; Write the Vin parameters.
;
dWrite_Civic saveVidInSize(a3),#VidInSize ; Write out the size parameter for video in ("BigSmall Video").
dWrite_Civic saveVinHFP(a3),#VInHFP ; Write out the horizontal timing parameters.
dWrite_Civic saveVinHFPD(a3),#VInHFPD ;
dWrite_Civic saveVinHAL(a3),#VInHAL ;
dWrite_Civic saveVinVFP(a3),#VInVFP ;
dWrite_Civic saveVinVAL(a3),#VInVAL ;
Move.w (Sp)+,Sr ; Restore the interrupt level.
; Exit subroutine, write back stack to csRect in case of clipping
CSetVRectGoodExit
Move.l (Sp)+,A6 ; Restore our used variable
Moveq #0,D0 ; Set noerr return
CSetVRectExit
Rts ; and go back
CRectGotClipped
Move.l (Sp)+,A6 ; Restore our used variable
Moveq #1,D0 ; Set error return
Bra.s CSetVRectExit ; and go back
;---------------------------------------------------------------------
;
; This routine is used to program Civic when video-in is enabled, depending
; on the what video-in mode and the graphics mode are
;
; A3 = Pointer to CivicVidPrivates Table
; A4 = Pointer to VidParams
; A5 = Pointer to VDACBase
;
; D7 = CLUT value with desired graphics and video-in bpp
; D0,D1,D2,D3,D4,D6,D7 (not preserved)
;
;
;---------------------------------------------------------------------
CSetVidInModeGuts
;
; SubRoutine to change depths when video in is enabled
;
Clr.w D4 ; D4 contains the GSCDivideAdjust field
Clr.w D6 ; D6 contains the VSCDivideAdjust field
Move.b D7,D1 ; Get a copy of the desired bpp
Andi.w #mCivicGrBpp,D1 ; Look at the graphics bpp (#mCivicGrBpp = $07). Save for later.
Btst #fCivicVidInBpp,D7 ; Look at the Video-in Bpp
Beq CVidIn8bppMode ; do an 8bpp mode
; We're doing video-in 16bpp here
Cmp.w #vCivicGr16Bpp,D1 ; Is the graphics in 16bpp
Beq @GSCOK ; if it is not the GSCDivide value from the parameters
Moveq #1,D4 ; needs to be increased by one.
@GSCOK Adda.w #CVPHdrSize,A4 ; Skip past the header info
Move.l A4,A5 ; Make a copy of the base vidparams field (Use A5 to point to the horizontal values)
Move.w #CBPSize,D0 ; Get the size of each entry
Mulu D1,D0 ; We want the correct bpp entry
Adda.l D0,A4 ; Add it to our base, A4 now points to the bpp entry
Move.w #CBPSize,D0 ; Get the size of each entry
Mulu #4,D0 ; We want the 4th bpp entry
Adda.l D0,A5 ; Add it to our base, A5 now points to the 16bpp entry
; Make sure that the 16bpp entry has video-in enabled, If not, look at the 32bpp entry.
Tst.w cbpBusSize(A5) ; This tells us if video-in is enabled
Beq.w @goodEntry ; when 0, video-in is enabled
Adda.l #CBPSize,A5 ; if the 16bpp has no video-in, the 32bpp entry will have the double parameters
@goodEntry
Bra CivicVidModeHWParams ; A4 -> ptr to desired bpp entry, A5->desired horiz parameters entry.
CVidIn8bppMode
; We're doing video-in 8bpp.
Cmp.w #vCivicGr16Bpp,D1 ; Is the graphics in 16bpp
Bne @CVidIn8Gr8bpp ; if not, go do 8bpp stuff
Move.w #1,D6 ; D6 contains the value for VSCDivide
@CVidIn8Gr8bpp
Adda.w #CVPHdrSize,A4 ; Skip past the header info
Move.w #CBPSize,D0 ; Get the size of each entry
Mulu D1,D0 ; Get the entry we want
Adda.l D0,A4 ; We want the 0th entry
Move.l A4,A5 ; Point A5 to the desired entry for the horizontal parameters.
CivicVidModeHWParams
; Calculate the baseAddress to put into Civic
Move.l saveBaseAddr(A3),D2 ; Get our BaseAddress
Lsr.l #5,D2 ; Normalize it for Civic
Andi.l #$FF,D2 ; Only 8 bits are valid
; Wait for the next VBL before trying to switch depths.
;
Move.w Sr,-(Sp) ; Save the current interrupt level.
Bsr CivicWaitVSync ; Wait for the next VBL.
; Switch the framebufferÕs depth.
;
; Note: cbpBusSize(A5) might not have the correct value. Always program it 0 here. <LW15>
Move.w d2,-(Sp) ; Save d2 'cause we'll trash it <LW15>
clr.w d2 ; Bus Size is 0 in this case <LW15>
dWrite_Civic d2,#BusSize ; Write the BusSize parameter <LW14><LW15>
Move.w (Sp)+,d2 ; restore d2 <LW15>
dWrite_Civic cbpHSerr(A5),#HSerr ; Write out the horizontal timing parameters.
dWrite_Civic cbpHlfLn(A5),#HlfLn ;
dWrite_Civic cbpHEq(A5),#HEq ;
dWrite_Civic cbpHSP(A5),#HSP ;
dWrite_Civic cbpHBWay(A5),#HBWay ;
dWrite_Civic cbpHAL(A5),#HAL ;
dWrite_Civic cbpHFP(A5),#HFP ;
dWrite_Civic cbpHPix(A5),#HPix ;
Add.w cbpGSCDivide(A4),D4 ; Add GSCDivide to 1 or 0, depending on the factor
dWrite_Civic D4,#GSCDivide ; Write it out
dWrite_Civic cbpRowWords(A4),#RowWords ;
dWrite_Civic D2,#BaseAddr ;
dWrite_Civic cbpAdjF1(A4),#AdjF1 ;
dWrite_Civic cbpAdjF2(A4),#AdjF2 ;
dWrite_Civic cbpPipeD(A5),#PipeD ;
dWrite_Civic D6,#VSCDivide ; and VSCDivide
; Now, reset the timing generator.
;
Bsr CivicWaitVSync ; Wait for the next VBL.
Jsr CivicReset ; Reset Civic (Needs A3 = vidprivates, trashes A0)
Move.w (Sp)+,Sr ; Restore the interrupt level.
Rts
;-------------------------------------------------------------
; This routine resets Civic
;-------------------------------------------------------------
CivicReset
; Reset of Civic
Move.l saveCivicBase(A3),A0 ; Point to the base of Civic.
Move.l #0,Civic_Reset(A0) ; Reset Casio.
Move.l #0,Civic_Reset(A0) ; Reset Casio.
Move.l #0,Civic_Reset(A0) ; Reset Casio.
Move.l #0,Civic_Reset(A0) ; Reset Casio.
Move.l #0,Civic_Reset(A0) ; Reset Casio.
Move.l #1,Civic_Reset(A0) ;
Move.l #1,Civic_Reset(A0) ;
Move.l #1,Civic_Reset(A0) ;
Move.l #1,Civic_Reset(A0) ;
Move.l #1,Civic_Reset(A0) ;
Move.l #0,Civic_Reset(A0) ;
Move.l #0,Civic_Reset(A0) ;
Move.l #0,Civic_Reset(A0) ;
Move.l #0,Civic_Reset(A0) ;
Move.l #0,Civic_Reset(A0) ;
Move.l #1,Civic_Reset(A0) ;
Move.l #1,Civic_Reset(A0) ;
Move.l #1,Civic_Reset(A0) ;
Move.l #1,Civic_Reset(A0) ;
Move.l #1,Civic_Reset(A0) ;
Rts
;---------------------------------------------------------------------
;
; Wait5ms
; Entry: Not Used
; Exit: D0 destroyed
;---------------------------------------------------------------------
;
; This loop will wait 5 milliseconds before returning. It is used for the Clifton clock chip
Wait5ms Move.l #(-5)<<16,d0 ; outer loop count 500*1ms
@outer Move.w TimeDBRA,d0 ; inner loop count 1ms
@inner dbra d0,@inner ; wait 1ms
Addq.l #1,d0 ; increment outer loop counter
Bne.s @outer ; wait 5*1ms
rts ; the long wait is over
;--------------------------------------------------------------------- <LW17> #PUMA
; <LW17> #PUMA
; IsItPUMA <LW17> #PUMA
; Entry: A4 (Endeavor Base) <LW17> #PUMA
; Exit: D0-D2 destroyed <LW17> #PUMA
;--------------------------------------------------------------------- <LW17> #PUMA
; <LW17> #PUMA
; This routine will try to read the ID register from Clifton or PUMA. Clifton does not <LW17> #PUMA
; have one, so it should read all 1's, where PUMA does. The routine will exit with the <LW17> #PUMA
; condition code set to 0 if it's a PUMA. <LW17> #PUMA
; <LW17> #PUMA
IsItPUMA ; <LW17> #PUMA
move.l #ControlWordSize-1,D2 ; Get the loop counter <LW17> #PUMA
move.l #ReadPUMAID,D1 ; Enable MuxRef/Enable PROG Register <LW17> #PUMA
@LoadID ; <LW17> #PUMA
Move.l #1,D0 ; Set up the mask for the bit <LW17> #PUMA
And.l D1,D0 ; Transfer the first bit to D0 <LW17> #PUMA
Move.b D0,EndeavorM(A0) ; write the bit out to Clifton <LW17> #PUMA
lsr.l #1,D1 ; get the next bit <LW17> #PUMA
Dbra D2,@LoadID ; Éfor the whole word <LW17> #PUMA
; <LW17> #PUMA
Move.l #(8-1),D2 ; The loop counter <LW17> #PUMA
clr.b D0 ; We'll store the ID here <LW17> #PUMA
@ReadID Move.b EndeavorM(A0),D1 ; Read a bit <LW17> #PUMA
Andi.b #1,D1 ; Mask all but the 0th bit <LW17> #PUMA
Or.b D1,D0 ; Or into our save register <LW17> #PUMA
ror.b #1,D0 ; And get ready to accept the new bit <LW17> #PUMA
Dbra D2,@ReadID ; Éfor the whole word <LW17> #PUMA
; <LW17> #PUMA
cmpi.b #PUMAVer1Id,D0 ; Is it our version 1 ID <LW17> #PUMA
rts ; <LW17> #PUMA
; <LW17> #PUMA
;-------------------------------------------------------------
; The Interrupt handler for the Civic Built-In Video
;-------------------------------------------------------------
; On entry A1 contains the pointer to the driver's private storage
CivicBeginIH
Move.l A0,-(Sp) ; Save work registers (according to IM V).
Move.l D1,-(Sp) ; (Two Moves are faster than a Movem.)
Move.l saveCivicBase(A1),A0 ; Point to the base of Civic.
Move.l Civic_VBLInt(A0),D0 ; Is this a VBL Interrupt
Btst #0,D0 ; Only bit 0 is valid
Bne @ItsAVBL ; Active high interrupt
; If it's not a VBL, then it has to be a VDC interrupt. Just exit without saying we handle the interrupt.
* Bra.s @InterruptNotServiced
@InterruptNotServiced
Moveq #0,D0 ; Signal that the interrupt was NOT serviced
Bra @ExitVBLHandler
@ItsAVBL
Clr.l Civic_VBLClr(A0) ; Clear this interrupt.
Move.l #1,Civic_VBLClr(A0) ; Re-enable VBLs.
Moveq #0,D0 ; Set up for Slot $0É
Jsr ([jVBLTask]) ; Éand call the VBL Task Manager.
@InterruptServiced
Moveq #1,D0 ; Signal that the interrupt was serviced
@ExitVBLHandler
Move.l (Sp)+,D1 ; Restore our work registers.
Move.l (Sp)+,A0 ; (Two Moves are faster than a Movem.)
Rts ; Return to caller.
END