298 lines
7.9 KiB
Plaintext
298 lines
7.9 KiB
Plaintext
|
;--------------------------------
|
||
|
; program dma
|
||
|
;--------------------------------
|
||
|
sb_set_dma:
|
||
|
mov ebx,[sound_dma]
|
||
|
lea eax,[ebx+4] ;mask required channel
|
||
|
cmp bl,4
|
||
|
ja .use_second_dma_controller
|
||
|
jb @f
|
||
|
.dma_setup_error:
|
||
|
if DEBUG
|
||
|
mov esi,msgErrDMAsetup
|
||
|
call SysMsgBoardStr
|
||
|
end if
|
||
|
mov dword[esp],START.stop
|
||
|
ret
|
||
|
@@:
|
||
|
if use_cli_sti
|
||
|
cli ;here to minimize time with disabled ints
|
||
|
end if
|
||
|
out 0xA,al ;mask required channel
|
||
|
|
||
|
xor eax,eax
|
||
|
out 0xC,al ;clear byte pointer flip-flop register
|
||
|
|
||
|
lea eax,[ebx+0x58] ;auto-init mode for channel (ebx)
|
||
|
out 0xB,al ;DMA channel 0-3 mode register
|
||
|
|
||
|
movzx edx,byte[ebx+dma_table] ;page register
|
||
|
mov al,DMAPage
|
||
|
out dx,al
|
||
|
|
||
|
lea edx,[ebx*2] ;DMA channel 0-3 base address
|
||
|
|
||
|
mov al,0 ;LSB is 0
|
||
|
out dx,al
|
||
|
|
||
|
; mov al,0 ;MSB is 0 too
|
||
|
out dx,al
|
||
|
|
||
|
inc edx ;DMA channel 0-3 byte count
|
||
|
|
||
|
mov al,((sb_buffer_size-1) and 0xff)
|
||
|
out dx,al
|
||
|
|
||
|
mov al,((sb_buffer_size-1) shr 8) ;it is the same
|
||
|
out dx,al
|
||
|
|
||
|
mov eax,ebx ;unmask DMA channel
|
||
|
out 0xA,al
|
||
|
|
||
|
if use_cli_sti
|
||
|
sti
|
||
|
end if
|
||
|
ret
|
||
|
|
||
|
.use_second_dma_controller:
|
||
|
cmp bl,7
|
||
|
ja .dma_setup_error
|
||
|
|
||
|
sub bl,4
|
||
|
sub al,4
|
||
|
if use_cli_sti
|
||
|
cli ;here to minimize time with disabled ints
|
||
|
end if
|
||
|
out 0xD4,al ;mask required channel
|
||
|
|
||
|
xor eax,eax
|
||
|
out 0xD8,al ;clear byte pointer flip-flop register
|
||
|
|
||
|
lea eax,[ebx+0x58] ;auto-init mode for channel (ebx+4)
|
||
|
out 0xD6,al ;DMA channel 4-7 mode register
|
||
|
|
||
|
movzx edx,byte[ebx+dma_table+4] ;page register
|
||
|
mov al,DMAPage
|
||
|
out dx,al
|
||
|
|
||
|
lea edx,[ebx*4+0xC0] ;DMA channel 4-7 base address
|
||
|
|
||
|
mov al,0 ;LSB is 0 ;for 16bit DMA this contains
|
||
|
out dx,al ;A1-A8 lines of address bus, A0 is zero
|
||
|
|
||
|
; mov al,0 ;MSB is 0 too ;for 16bit DMA this contains
|
||
|
out dx,al ;A9-A16 lines of address bus
|
||
|
|
||
|
inc edx
|
||
|
inc edx ;DMA channel 4-7 16bit word count
|
||
|
|
||
|
mov al,(((sb_buffer_size/2)-1) and 0xff)
|
||
|
out dx,al
|
||
|
|
||
|
mov al,(((sb_buffer_size/2)-1) shr 8)
|
||
|
out dx,al
|
||
|
|
||
|
mov eax,ebx ;unmask DMA channel
|
||
|
out 0xD4,al
|
||
|
|
||
|
if use_cli_sti
|
||
|
sti
|
||
|
end if
|
||
|
ret
|
||
|
;-------------------------------------------------------------------------------
|
||
|
; out byte to SB DSP's write port
|
||
|
;-------------------------------------------------------------------------------
|
||
|
macro sb_out data_to_out {
|
||
|
@@:
|
||
|
in al,dx
|
||
|
test al,al ;is DSP busy?
|
||
|
js @b ;it's busy
|
||
|
mov al,data_to_out ;it's free
|
||
|
out dx,al
|
||
|
}
|
||
|
;-------------------------------------------------------------------------------
|
||
|
; stop playing
|
||
|
;-------------------------------------------------------------------------------
|
||
|
proc sb_stop
|
||
|
mov edx,[sb_base_port]
|
||
|
add dl,0xC
|
||
|
sb_out 0xD3 ;turn the speaker off
|
||
|
sb_out 0xDA ;exit 8bit DMA
|
||
|
sb_out 0xD9 ;exit 16bit DMA
|
||
|
ret
|
||
|
endp
|
||
|
;-------------------------------------------------------------------------------
|
||
|
; start playing
|
||
|
;-------------------------------------------------------------------------------
|
||
|
proc sb_play
|
||
|
and [int_flip_flop],0
|
||
|
mov edx,[sb_base_port]
|
||
|
add dl,0xC
|
||
|
sb_out 0xD1 ;turn speaker on
|
||
|
; sb_out 0x48 ;set DSP transfer size ;for older cards, not supported
|
||
|
; ;in this version
|
||
|
; mov ax,32767 ;(64k)/2-1
|
||
|
;@@: ;out the low byte...
|
||
|
; in al,dx
|
||
|
; test al,al ;is DSP busy?
|
||
|
; js @b ;it's busy
|
||
|
; out dx,al
|
||
|
|
||
|
; mov al,ah ;...then the high byte
|
||
|
;@@:
|
||
|
; in al,dx
|
||
|
; test al,al ;is DSP busy?
|
||
|
; js @b ;it's busy
|
||
|
; out dx,al
|
||
|
|
||
|
; sb_out 0x1C ;auto-init 8bit playback
|
||
|
|
||
|
; 0xBXh - 16 bit DMA mode
|
||
|
; ||||
|
||
|
sb_out 10110110b ;bCommand
|
||
|
; ||||
|
||
|
; |||+-reserved
|
||
|
; ||+--turn FIFO on (0 for off)
|
||
|
; |+---auto-init mode on (0 for off)
|
||
|
; +----A/D: 0-output, 1-input
|
||
|
; +------stereo on
|
||
|
; |+-----unsigned (1 for signed)
|
||
|
; ||
|
||
|
sb_out 00110000b ;bMode
|
||
|
; || ||||
|
||
|
; ---------reserved
|
||
|
;wSize is a number of 16bit samples less 1. For auto-init mode each half
|
||
|
;buffer is (64k)/2 bytes long and, obviously, contains ((64k)/2)/2 samples
|
||
|
sb_out (((sb_buffer_size/2/2)-1) and 0xFF) ;wSize.LowByte
|
||
|
sb_out (((sb_buffer_size/2/2)-1) shr 8) ;wSize.HighByte
|
||
|
ret
|
||
|
endp
|
||
|
;-------------------------------------------------------------------------------
|
||
|
; reset DSP
|
||
|
;-------------------------------------------------------------------------------
|
||
|
proc sb_reset
|
||
|
and [int_flip_flop],0
|
||
|
mov edx,[sb_base_port]
|
||
|
add dl,6
|
||
|
mov al,1 ;start DSP reset
|
||
|
|
||
|
if use_cli_sti
|
||
|
cli ;here to minimize time with disabled ints
|
||
|
end if
|
||
|
out dx,al
|
||
|
mov ecx,40 ;wait at least 3 microsec.
|
||
|
@@:
|
||
|
in al,dx
|
||
|
loop @b
|
||
|
|
||
|
xor eax,eax ;stop DSP reset
|
||
|
if use_cli_sti
|
||
|
sti
|
||
|
end if
|
||
|
out dx,al
|
||
|
ret
|
||
|
endp
|
||
|
|
||
|
;-------------------------------------------------------------------------------
|
||
|
; set the rate for playing, enable stereo
|
||
|
;-------------------------------------------------------------------------------
|
||
|
proc sb_setup
|
||
|
mov edx,[sb_base_port]
|
||
|
add dl,0xC
|
||
|
sb_out 40h ;set time constant, this is for old cards
|
||
|
sb_out sb_tc
|
||
|
|
||
|
sb_out 41h ;set sound rate, this can only SB16
|
||
|
sb_out (sb_out_rate shr 8) ;first high byte (MSB)
|
||
|
sb_out (sb_out_rate and 0xff) ;then low byte (LSB)
|
||
|
|
||
|
; mov al,0xE ;for older cards, not supported in this version
|
||
|
; sub dl,(0xC-4) ;talk to SB's mixer
|
||
|
; out dx,al ;select this register of the mixer
|
||
|
; mov ecx,6 ;wait for the chip
|
||
|
;@@:
|
||
|
; in al,dx
|
||
|
; loop @b
|
||
|
|
||
|
; inc edx ;now read the data port
|
||
|
; in al,dx
|
||
|
; or al,22h ;turn on stereo
|
||
|
; mov ah,al
|
||
|
|
||
|
; mov al,0xE
|
||
|
; dec edx ;talk to SB's mixer
|
||
|
; out dx,al ;select this register of the mixer
|
||
|
|
||
|
; mov ecx,6 ;wait for the chip
|
||
|
;@@:
|
||
|
; in al,dx
|
||
|
; loop @b
|
||
|
|
||
|
; inc edx ;now send data to the data port
|
||
|
; mov al,ah
|
||
|
; out dx,al
|
||
|
|
||
|
; dec edx
|
||
|
; mov ecx,35 ;wait for the chip
|
||
|
;@@:
|
||
|
; in al,dx
|
||
|
; loop @b
|
||
|
ret
|
||
|
endp
|
||
|
|
||
|
;-------------------------------------------------------------------------------
|
||
|
; set master volume of SB mixer, note, not only SB16 but SBPro and older
|
||
|
; this is the first step to more full support for hardware
|
||
|
;-------------------------------------------------------------------------------
|
||
|
;in: eax in range [-10000;0] - master volume for _both_ channels
|
||
|
;note that x*3*17/2000 and x*3/2000*17 are not the same numbers,
|
||
|
;because we count in integers
|
||
|
proc sb_set_master_vol
|
||
|
mov [sb_master_vol],eax
|
||
|
add eax,10000 ;SB sound level rise from 0 to MAX_LEVEL
|
||
|
lea eax,[eax+eax*2] ;*3
|
||
|
mov ebx,2000 ;divisor
|
||
|
xor edx,edx
|
||
|
cmp byte[sb_DSP_version_int],4
|
||
|
jae @f ;SBPro's MAX_LEVEL is 15, but we *11 because
|
||
|
;volume byte looks like that: 0xLR, where L - left
|
||
|
;channel volume, R - right, 0<=R,L<=15
|
||
|
div ebx
|
||
|
imul eax,17
|
||
|
mov edx,[sb_base_port]
|
||
|
push eax ;here for optimisation
|
||
|
add dl,4
|
||
|
mov al,0x22 ;write mixer register 0x22
|
||
|
out dx,al
|
||
|
in al,dx ;wait for the chip ;6
|
||
|
in al,dx ;wait for the chip ;5
|
||
|
in al,dx ;wait for the chip ;4
|
||
|
in al,dx ;wait for the chip ;3
|
||
|
in al,dx ;wait for the chip ;2
|
||
|
in al,dx ;wait for the chip ;1
|
||
|
pop eax ;go!
|
||
|
inc edx
|
||
|
out dx,al
|
||
|
ret
|
||
|
@@: ;SB16's MAX_LEVEL is 255
|
||
|
imul eax,17
|
||
|
div ebx
|
||
|
mov edx,[sb_base_port]
|
||
|
push eax ;here for optimisation
|
||
|
add dl,4
|
||
|
mov al,0x30 ;left speaker
|
||
|
out dx,al
|
||
|
pop eax ;<--+
|
||
|
inc edx ; \/
|
||
|
push eax ;here for optimisation
|
||
|
out dx,al ;write
|
||
|
dec edx
|
||
|
mov al,0x31 ;right speaker
|
||
|
out dx,al
|
||
|
pop eax
|
||
|
inc edx
|
||
|
out dx,al ;write
|
||
|
ret
|
||
|
endp
|
||
|
;-------------------------------------------------------------------------------
|