;$Author:   DCODY  $
;$Date:   24 Sep 1992 08:51:56  $
;$Header:   X:/sccs/fm/3812a.asv   1.4   24 Sep 1992 08:51:56   DCODY  $
;$Log:   X:/sccs/fm/3812a.asv  $
;  
;     Rev 1.4   24 Sep 1992 08:51:56   DCODY
;  changed MVGetHardware to mvGetHardware
;  
;     Rev 1.3   20 Jul 1992 11:40:56   DCODY
;  call to mvGetHWVersion requests active I/O detection.
;  
;     Rev 1.2   17 Jul 1992 13:55:46   DCODY
;  base I/O address can now move...
;  
;     Rev 1.1   27 Jun 1992 14:47:08   DCODY
;  fixed FMsplit for the opl3, and outdual3812 now programs one
;  side of the OPL3 at a time.
;  
;     Rev 1.0   26 Jun 1992 14:21:58   BCRANE
;  Initial revision.
;  
;     Rev 1.3   26 Jun 1992 14:12:08   DCODY
;  added the parameter to the gethwversion call.
;  
;     Rev 1.2   25 Jun 1992 21:11:10   DCODY
;  finished the init routine. Made timing loops variable based
;  upon the installed FM chip.
;  
;     Rev 1.1   23 Jun 1992 16:32:30   DCODY
;  PAS2 update
;  
;     Rev 1.0   15 Jun 1992 09:39:46   BCRANE
;  Initial revision.
;$Logfile:   X:/sccs/fm/3812a.asv  $
;$Modtimes$
;$Revision:   1.4  $

        Title 3812/OPL3 Access Routines

;   /*\
;---|*|---===< 3821A.ASM >====----
;---|*|
;---|*| This is the output routine to write data to the twin 3821 chips,
;---|*| or OPL-3 4OP synth chip.
;---|*|
;---|*| Media Vision, Inc. Copyright (c) 1991,1992. All Rights Reserved.
;---|*|
;   \*/

	.xlist
	include model.inc
        include masm.inc
	include state.inc
        include target.inc
	include common.inc
	.list

        .data

	extrn	_MVHWVersionBits   :word
	extrn	_MVTranslateCode   :word
	extrn	mvhwShadowPointer  :dword

indexwrite	dw	05		; 3812 index write delays
datawrite       dw      35              ; 3812 data write delays
splitmode	db	0		; 00 = mono, 01 = stereo

	.code

	externADDR   mvGetHWVersion
	externADDR   MVInitStatePtr

;
;   /*\
;---|*|---===< mvFMInitMode (int) >====----
;---|*|
;---|*| This routine initializes the Dual 3812/OPL-3 chip
;---|*|
;---|*| Entry Conditions:
;---|*|     wParm1 = 0 to setup for mono, 1 to setup for sterero
;---|*|
;---|*| Exit Conditions:
;---|*|     AX,BX,CX,DX modified
;---|*|
;   \*/
	public	mvFMInitMode
mvFMInitMode	proc
	push	bp
	mov	bp,sp
;
; validate the hardware if not done already.
;
	cmp	[_MVHWVersionBits],-1	; check to see if we know the hardware
	jnz	@F
	mov	ax,USE_ACTIVE_ADDR
	push	ax
	call	mvGetHWVersion		; get the hardware version
	add	sp,2
        cmp     al,-1                   ; everything here?
	jz	mvmfexit		; no, exit out now...
    ;
    @@:
;
; validate the state table pointer
;
	cmp	word ptr [mvhwShadowPointer+2],0
	jnz	@F
	call	MVInitStatePtr
;
; setup I/O delays based upon the installed FM chip
;
	test	[_MVHWVersionBits],bMVOPL3 ; defaults are setup for 3812
	jz	@F			   ; which are okay, exit out now...
	mov	[indexwrite],3		   ; OPL3 index write delays
	mov	[datawrite], 3		   ; OPL3 data	write delays
;
@@:
;
; set the chips in mono mode, then flush them.
;
	sub	ax,ax			; set the chip(s) in mono mode
	mov	splitmode,al
	call	FMsplit

	mov	dx,LFMADDR		; flush the left/right side
	xor	dx,[_MVTranslateCode]	; translate to the board address
	call	flushit
;
; now, split the chips into stereo mode if requested to do so
;
	cmp	wptr wParm1,0		; all done?
	jz	mvmfexit		; yes, exit

	mov	al,1			; split it now
        mov     splitmode,al
	call	FMsplit
;
mvmfexit:
	pop	bp
        ret

mvFMInitMode	endp

;
;   /*\
;---|*|---===< outdual3812(int,int,int) >====----
;---|*|
;---|*| This routine writes index/data to
;---|*| both chips in an interleaved fashion.
;---|*|
;---|*| Entry Conditions:
;---|*|     wParm1 is the chip index value
;---|*|     wParm2 is the left	FM chip data
;---|*|     wParm3 is the right FM chip data
;---|*|
;---|*| Exit Conditions:
;---|*|     AX,DX,CX modified
;---|*|
;   \*/

	public	outdual3812
outdual3812	proc
;
; this is kinda screwy, but if we're in mono mode, don't write to both sides
;
	cmp	splitmode,0		; are we doing both?
	jjnz	outleft3812		; no, just do the left side...
;
; frame the stack and continue.
;
	push	bp
	mov	bp,sp
;
; write the index to both chips
;
        mov     dx,LFMADDR              ; get the left 3812 address
	xor	dx,[_MVTranslateCode]	; translate to the board address
        mov     al,wParm1               ; get the index value
;
; special case the OPL3 since it only really has one index register.
;
	test	[_MVHWVersionBits],bMVOPL3 ; defaults are setup for 3812
	jnz	outtoopl3		   ; which are okay, exit out now...
;
; the dual 3812s can have interleaved I/O to speed up the pace
;
	out	dx,al			; output to both chips
	add	dx,2
	out	dx,al
;
; wait the proper delays for either FM chip
;
	mov	cx,[indexwrite]
    ;
    @@:
        in      al,dx
	loop	@B
;
; write the data out to the chip now
;
	dec	dx			; move back to the left FM data reg
	mov	al,byte ptr wParm2
	mov	ah,byte ptr wParm3

	out	dx,al			; write the data out
	add	dx,2
	xchg	ah,al
	out	dx,al
;
; wait the proper delays for either FM chip
;
	mov	cx,[datawrite]
    ;
    @@:
	in	al,dx
	loop	@B

	pop	bp
	ret
;
outtoopl3:
;
; do the left side of the OPL3 first
;
	; write the left index

        out     dx,al                   ; output to both chips
	mov	cx,[indexwrite]
    ;
    @@:
        in      al,dx
	loop	@B

	; write the left data

        inc     dx                      ; move to the left FM data reg
	mov	al,wParm2
	out	dx,al			; write the data out
	mov	cx,[datawrite]
    ;
    @@:
	in	al,dx
	loop	@B
;
; do the right side of the OPL3 next
;
	; write the right index

	inc	dx
        mov     ax,wParm1               ; get the index value
        out     dx,al                   ; output to both chips
	mov	cx,[indexwrite]
    ;
    @@:
        in      al,dx
	loop	@B

	; write the right data

        inc     dx                      ; move to the left FM data reg
	mov	al,wParm3

	out	dx,al			; write the data out
	mov	cx,[datawrite]
    ;
    @@:
	in	al,dx
	loop	@B

	pop	bp
	ret

outdual3812	endp

;
;   /*\
;---|*|---===< outleft3812(int,int) >====----
;---|*|
;---|*| This routine writes index/data to the left FM chip.
;---|*|
;---|*| Entry Conditions:
;---|*|     wParm1 is the left FM index
;---|*|     wParm2 is the left FM chip data
;---|*|
;---|*| Exit Conditions:
;---|*|     AX,DX,CX modified
;---|*|
;   \*/

	public	outleft3812
outleft3812	proc
	push	bp
	mov	bp,sp
;
; write the index to both chips
;
        mov     dx,LFMADDR              ; get the left 3812 address
	xor	dx,[_MVTranslateCode]	; translate to the board address
;
fm_common_output label near
;
; output the index to the single chip
;
        mov     ax,wParm1               ; get the index value
	out	dx,al			; output to both chips
	mov	cx,[indexwrite]
;
@@:
        in      al,dx                   ; slow down for the index to settle
	loop	@B

	inc	dx			; move to the data register

        mov     ax,wParm2
	out	dx,al			; write the data out

	mov	cx,[datawrite]
;
@@:
	in	al,dx
	loop	@B

	pop	bp
	ret

outleft3812	endp

;
;   /*\
;---|*|---===< outright3812(int,int) >====----
;---|*|
;---|*| This routine writes index/data to the right FM chip.
;---|*|
;---|*| Entry Conditions:
;---|*|     wParm1 is the right FM index
;---|*|     wParm1 is the right FM chip data
;---|*|
;---|*| Exit Conditions:
;---|*|     AX,DX,CX modified
;---|*|
;   \*/

	public	outright3812
outright3812	proc
	push	bp
	mov	bp,sp
;
; write the index to both chips
;
	mov	dx,RFMADDR		; get the right 3812 address
        xor     dx,[_MVTranslateCode]   ; translate to the board address
        jmp     short fm_common_output

outright3812	endp

;
;--------------------------==========================--------------------------
;--------------------------====< local routines >====--------------------------
;--------------------------==========================--------------------------
;

;
;   /*\
;---|*|---===< flushit >====----
;---|*|
;---|*| Reset both sides of the FM chip(s)
;---|*|
;---|*| Entry Conditions:
;---|*|     none
;---|*|
;---|*| Exit Conditions:
;---|*|     AX,BX,CX,DX modified
;---|*|
;   \*/
;
flushit proc	near
	mov	ax,1		; reg 1
	call	fmout

        inc     ax              ; reg 2
	call	fmout

        inc     ax              ; reg 3
	call	fmout

        inc     ax              ; reg 4
	call	fmout

        mov     al,8            ; reg 8
	call	fmout

        mov     al,20h          ; flush all others from reg 20 to reg FF
	mov	cx,0FFh-20h
;
@@:
	call	fmout
	inc	ax
	loop	@B

	ret

flushit endp

;
;   /*\
;---|*|---===< FMsplit >====----
;---|*|
;---|*| Split or combine the FM sides.
;---|*|
;---|*| Entry Conditions:
;---|*|     AL = 1 for stereo, 0 for mono
;---|*|
;---|*| Exit Conditions:
;---|*|     AX,BX,CX,DX modified
;---|*|
;   \*/
;
FMsplit proc    near
;
; record either MONO or STEREO in the state table
;
	push	es
	push	di
	les	di,[mvhwShadowPointer]	   ; we have to record in in the state
;
; maintain the split state fact in the old split FM bit
;
	mov	ah,al				 ; save an original copy
	cmp	al,1				 ; set carry if zero
	sbb	al,al				 ; al = FF for mono
	and	al,bMImonofm			 ; keep the bit if mono

        and     es:[di._audiomixr],NOT bMImonofm ; flush the bit
	or	es:[di._audiomixr],al		 ; maybe set it
	mov	al,es:[di._audiomixr]		 ; load a copy for old pas

	pop	di
	pop	es
;
; if OPL3, go do it's split, else just write out the new mixer setting
;
        test    [_MVHWVersionBits],bMVOPL3 ; defaults are setup for 3812
	jnz	splitopl3		   ; which are okay, exit out now...

	mov	dx,AUDIOMIXR		   ; get the mixer address
	xor	dx,[_MVTranslateCode]	   ; translate to the board address
	out	dx,al			   ; send the bits out to the h/w

        ret
;
splitopl3:
	mov	al,5			   ; send it to the right FM reg 5
	mov	dx,RFMADDR
        xor     dx,[_MVTranslateCode]      ; translate to the board address
	out	dx,al			   ; send the index

        mov     cx,[indexwrite]
    ;
    @@:
	in	al,dx			   ; wait the prescribed period
	loop	@B

	inc	dx
        mov     al,ah
	out	dx,al			   ; send the data byte

        mov     cx,[datawrite]
    ;
    @@:
	in	al,dx			   ; wait the prescribed period
	loop	@B

        ret

FMsplit endp

;
;   /*\
;---|*|---===< fmout >====----
;---|*|
;---|*| write to one of the chips.
;---|*|
;---|*| Entry Conditions:
;---|*|     DX holds the base address (left side or right side)
;---|*|     AL holds the index register value
;---|*|     AH holds the data  register value
;---|*|
;---|*| Exit Conditions:
;---|*|     no registers modified
;---|*|
;   \*/
;
fmout   proc    near
	push	ax
	push	cx

	out	dx,al
	mov	cx,[indexwrite]
;
@@:
	in	al,dx
	loop	@B

	xchg	ah,al
	inc	dx
	out	dx,al

        mov     cx,[datawrite]
;
@@:
	in	al,dx
	loop	@B

	dec	dx

	pop	cx
	pop	ax
	ret

fmout	endp

        end

