home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C!T ROM 5
/
ctrom5b.zip
/
ctrom5b
/
PROGRAM
/
DIVERSEN
/
DOS32V3B
/
LIB
/
GUS.ASM
< prev
next >
Wrap
Assembly Source File
|
1995-03-08
|
27KB
|
770 lines
;--------------------------------------------------------------------------;
; DOS32 32BIT DOS EXTENDER LIBRARY Gravis Ultrasound Routines ;
; ;
; Written by Adam Seychell ;
; ;
; ;
; Last modified 3rd March 1995 ;
; ;
;--------------------------------------------------------------------------;
; Note The "GF1" is the Ultrasounds programable Synthesizer chip for the
; 32 multi-timbral digital 16bit CD quality voices with independed volume
; ramping, panning.
;
.386
.Model flat
.Code
Include GUS.INC ; Define all the publics symbols
outp MACRO port,value
mov al,value
mov edx,dword ptr port
out dx,al
ENDM
FALSE equ 0
TRUE equ 1
;╒═════════════════════════════════════════════════════════════════════════╕
;│ THE GRAVIS UILTRASOUND PORT ADDRESS VARIBLES │
;│ │
;│ These 12 data vaibles below contian the ultrasounds port addresses. │
;│ See the SDK for what each port does. These varibles will be initalized │
;│ on the first successful call to the Ultrasound_Reset routine in this │
;│ library. │
;│ * Do not use these port address varibles until they are initalized as │
;│ otherwise they will contian wrong values. │
;└─────────────────────────────────────────────────────────────────────────┘
align 4
The_Ultrasound_port_Addresses LABEL dword
GF1_Voice_Select dw 102h ; GF1 Synthesizer
GF1_REG_Select dw 103h
GF1_Data_Low dw 104h
GF1_Data_High dw 105h
GF1_IRQ_status dw 006h
GF1_DRAM dw 107h
GF1_TIMER_Ctrl dw 008h
GF1_TIMER_Data dw 009h
Midi_control dw 100h ; MIDI Interface
Midi_Data dw 101h
Mix_control dw 000h ; BOARD CONTROL ONLY
IRQDMA_Ctrl dw 00Bh
Ultrasound_ports_ends LABEL dword
dma_reg_list db 0,1,0,2,0,3,4,5
irq_reg_list db 0,0,1,3,0,2,0,4,0,0,0,5,6,0,0,7
GUS_Base_port dw 0h
ULTRASND_string db 'ULTRASND='
GUSdetected_flag db False
;╒═════════════════════════════════════════════════════════════════════════╕
;│ GET THE DEFAULT SETTING OF THE GRAVIS UILTRASOUND │
;│ │
;│ │
;│ Looks for the environment varible "ULTRASND" for the default settings │
;│ of the Ultrasound. │
;│ │
;│ IN: nothing │
;│ │
;│ OUT: Carry is set if couldn't find environment or it has invalid │
;│ settings. │
;│ │
;│ Otherwise the carry flag is cleared and; │
;│ BL = GF1 IRQ number ( IRQ is either 0,2,3,5,7,11,12 or 15 ) │
;│ BH = MIDI IRQ number │
;│ CL = DMA Playback channel ( DMA is either 0,1,3,5,6 or 7 ) │
;│ CH = DMA Record channel │
;│ DX = Port Address ( 210h,220h,230h,240h,250h or 260h ) │
;│ │
;└─────────────────────────────────────────────────────────────────────────┘
GetUltraConfig PROC PASCAL USES EAX EDI
local Base_port :WORD
local dma_control :BYTE
local irq_control :BYTE
;
; Search for the string "ULTRASND=" in the environment area
;
Mov Ax,0EE02h
Int 31h ; Returns EDI -> environment
cld
Loop_Envir:
Mov esi,Offset ULTRASND_string
mov ecx,9
repe cmpsb
je Found_string
xor al,al
repne scasb
cmp byte ptr [edi],0
jne Loop_Envir
jmp No_ULTRASND
Found_string: ; EDI -> first char of string
mov ebx,[edi] ; OK, Found the string 'ULTRASND='
mov eax,ebx ; check for the valid paramters
and ebx,0ffff00ffh
cmp ebx,02C300032h ; '2x0,'
jne No_ULTRASND
shr eax,8
call get_digit ; eax = char digit in al
mov DX,ax ; load port address
shl edx,4
add dx,200h
sub al,1h ; port must be between 210h .. 260h
cmp al,5h
ja No_ULTRASND
add edi,4
;***** Get playback DMA channel ****
xor ecx,ecx
mov al,[edi]
call get_digit
cmp dma_reg_list[eax],0
je No_ULTRASND
mov CL,AL
inc edi
cmp byte ptr [edi],','
jne No_ULTRASND
;***** Get record DMA channel ****
inc edi
mov al,[edi]
call get_digit
cmp dma_reg_list[eax],0
je No_ULTRASND
mov CH,AL
inc edi
cmp byte ptr [edi],','
jne No_ULTRASND
; **** Get IRQ numnber GF1 ****
xor ebx,ebx
inc edi
cmp byte ptr [edi],'1'
jne J61
mov BL,10
inc edi
J61: mov al,[edi]
call get_digit
add al,bl
cmp al,15
ja No_ULTRASND
cmp IRQ_reg_list[eax],0 ; check for valid IRQ number
je No_ULTRASND
mov BL,AL
inc edi
cmp byte ptr [edi],','
jne No_ULTRASND
; **** Get MIDI IRQ numnber *****
inc edi
cmp byte ptr [edi],'1'
jne J62
mov BH,10
inc edi
J62: mov al,[edi]
call get_digit
add al,bh
cmp al,15
ja No_ULTRASND
cmp IRQ_reg_list[eax],0 ; check for valid IRQ number
je No_ULTRASND
mov BH,AL
;CHECK FOR STRING ENDING
inc edi
cmp byte ptr [edi],','
je got_it
cmp byte ptr [edi],' '
je got_it
cmp byte ptr [edi],0
jne No_ULTRASND
got_it:
clc
ret
No_ULTRASND:
stc
ret
get_digit:
sub al,'0'
jc No_digi
cmp al,9
ja No_digi
movzx eax,al
ret 0
No_digi:
add esp,4 ; ignore pushed EIP
stc
ret
GetUltraConfig ENDP
comment %
╒══════════════════════════════════════════════════════════════════════════╕
│ COMPLETELY RESET THE GRAVIS ULTRASOUND │
│ │
│ │
│ INPUT: │
│ BL = GF1 IRQ number ( IRQ must be 0,2,3,5,7,11,12 or 15 ) │
│ BH = MIDI IRQ number │
│ CL = DMA Playback channel ( DMA must be 0,1,3,5,6 or 7 ) │
│ CH = DMA Record channel │
│ DX = Base port address of the Ultrasound ( must be 2x0h ) │
│ │
│ │
│ OUTPUT: │
│ The function will fail if an illeagal DMA or IRQ number is selected │
│ and/or if the card has was not detected at the specified bass address │
│ │
│ If function successful the carry is cleared and │
│ the card is fully reset and all 32 voices are initalised │
│ EDI = DRAM installed on the ultrasound │
│ │
│ Other registers of the GF1 are set as follows │
│ LINE OUT enabled │
│ MIC IN disabled │
│ LINE IN disabled │
│ │
│NOTES: │
│ o This routine will probe the ultrasound on port address DX │
│ o This function should only need to be used once by your program. │
│ o Both PICs ( 8259's ) mask registers might be modified. │
│ o If the IRQ number is ZERO then the Ultrasound is programmed │
│ with that IRQ disabled. │
│ o If the DMA channel is ZERO then the Ultrasound is programmed │
│ with that DMA disabled. │
│ o EDI will contain the amount of RAM ( in bytes ) installed on the│
│ Ultrasound however it dos not do a complete RAM test. It will │
│ always return 0KB, 256KB ,512KB, 768KB or 1024KB. │
│ │
└───────────────────────────────────────────────────────────────────────── %
Ultrasound_Reset PROC PASCAL Uses EAX EBX ECX EDX ESI
local dma_control :BYTE
local irq_control :BYTE
local gf1 :Byte
local midi :Byte
local dram :Byte
local adci :Byte
pushad
cmp GUSdetected_flag, TRUE ; Don't detect if a GUS has
je @@skip_detection ; already been detected.
;
; check if DX = 2x0h. where x = 1,2,3,4,5,,,F
;
mov eax,edx
and ax,0F0Fh
cmp ax,0200h
jne invalid_setting
mov al,dl
and al,0F0h
jz invalid_setting
call Ultrasound_probe ; See if there's an ultrasound
jc invalid_setting
@@skip_detection:
and bx,0f0fh
and cx,0707h
mov GF1,bl ; Save IRQ's
mov midi,bh
;**** convert IRQ numbers into register value *****
movzx edx,bl
and dl,dl
jz Zero_irq1
mov dl,irq_reg_list[edx]
and dl,dl
jz invalid_setting
Zero_irq1: mov irq_control,dl
movzx edx,bh
and dl,dl
jz Zero_irq2
mov dl,irq_reg_list[edx]
and dl,dl
jz invalid_setting
shl dl,3
Zero_irq2: or irq_control,dl
cmp bh,bl ; Chech if both IRQ
jne diff_irqs ; are equal then
and bl,bl ;( Except when zero)
jz diff_irqs
and irq_control,0111b ; Clear Channel 2 IRQ
or irq_control,40h ; and turn on bit 6
diff_irqs:
;**** convert DMA number into register value *****
movzx edx,cl
and dl,dl
jz Zero_dma2
mov dl,dma_reg_list[edx]
and dl,dl
jz invalid_setting
Zero_dma1: mov dma_control,dl
movzx edx,ch
and dl,dl
jz Zero_dma2
mov dl,dma_reg_list[edx]
and dl,dl
jz invalid_setting
shl dl,3
Zero_dma2: or dma_control,dl
cmp ch,cl ; Chech if both DMAs
jne diff_dmas ; are equal then
and cl,cl ;( Except when zero)
jz diff_irqs
and dma_control,0111b ; Clear Channel 2 DMA
or dma_control,40h ; and turn on bit 6.
diff_dmas:
cli ; must not be disterbed
; The code below sets the DMA and IRQ settings of the Ultrasound
; It was sort of taken from the file RESET.C of GUS SDK V2.10
mov ecx,200h ; delay a bit
loop $
;/* Set up for Digital ASIC */
mov dx,GUS_base_port
add dx,0fh
mov al,5
out dx,al ; Seems to be a undocumented register
outp mix_control,00001011b
outp IRQDMA_Ctrl,0
mov dx,GUS_base_port
add dx,0fh
mov al,0
out dx,al
;/* First do DMA control register */
outp mix_control,00001011b
mov dx,IRQDMA_Ctrl
mov al,dma_control
or al,80h
out dx,al
;/* IRQ CONTROL REG */
outp mix_control,01001011b
outp IRQDMA_Ctrl,irq_control
;/* First do DMA control register */
outp mix_control,00001011b
outp IRQDMA_Ctrl,dma_control
;/* IRQ CONTROL REG */
outp mix_control,01001011b
outp IRQDMA_Ctrl,irq_control
;/* IRQ CONTROL, ENABLE IRQ */
;/* just to Lock out writes to irq\dma register ... */
outp GF1_Voice_Select,0
;/* enable output & irq, disable line & mic input */
outp mix_control,0001001b
;/* outp just to Lock out writes to irq\dma register ... */
outp GF1_Voice_Select,0
;
; Unmask the IRQ lines for the GF1 and MIDI IRQ settings
;
; NOTE: the pin labled IRQ 2 on the BUS connects to IRQ 9 of the PIC
; controllers. The IRQ 2 on the PIC is used for slave.
; The ultrasound SDK ( Software Development Kit ) says that the GUS can use
; IRQ 2 this means you must actualy hook IRQ 9.
in al,0A1h
mov ah,al
in al,21h
mov cl,GF1 ; Get GF1 IRQ
cmp cl , 2 ; gota put right IRQ 2
jne j3
mov cl,9
j3:
mov ebx,1
shl ebx,cl
not ebx
and eax,ebx
mov cl,MIDI ; Get MIDI IRQ
cmp cl , 2 ; gota put right IRQ 2
jne j4
mov cl,9
j4:
mov ebx,1
shl ebx,cl
not ebx
and eax,ebx
out 021h,al
mov al,ah
out 0A1h,al
sti
;
; Get amount of RAM installed on the sound card (return into EDI)
;
xor edi,edi
GetSizeloop:
mov ecx,edi ; Set DRAM I/O address
call UltraSetDRAM_address
in al,dx ; see if the DRAM locaion
mov cl,al ; can store some data
not al
out dx,al
in al,dx
cmp al,cl
jz NoDRAM
add edi,40000h
cmp edi,100000h ; the GF1 can only hold 1MB
jb GetSizeloop
NoDRAM: add edi,3ffffh ; align EDI on 256KB
and edi,NOT 3ffffh
;*** Initalise the UltraSound ****
call Ultrasound_Init
clc
ret
invalid_setting: ; jump here on error
stc
ret
;=================== Ultrasound reseted ============================
Ultrasound_Reset ENDP
comment %
╒══════════════════════════════════════════════════════════════════════════╕
│ INITALIZE THE ULTRASOUND'S VOICES │
│ │
│ │
│ │
│ IN: nothing │
│ │
│ OUT: All 32 voices have initalized , cleared buffered IRQ's │
│ enables line out │
│ Each of the 32 voices are set as follows │
│ │
│Frequency = 0 │
│Voice stoped │
│Bi-directional looping off │
│IRQs disabled │
│Current Volume = 0 │
│Active Number of Voices = 14 │
│ │
│NOTE: │
│ o This function will only be successful on a successful call │
│ to the "Ultrasound_Reset" routine │
└──────────────────────────────────────────────────────────────────────────┘%
Ultrasound_Init PROC PASCAL
cmp GUSdetected_flag, TRUE ; do only if gus has
jc GUSok ; been previously detected
stc
ret
GUSok:
pushad
;/* Pull a reset on the GF1 */
mov al,04Ch
mov cl,00000000b
call Set_GF1_ByteRegister
;/* Wait a little while ... */
mov ecx,10
J56: call GF1_delay
loop J56
;/* Release Reset */
mov al,04Ch
mov cl,00000001b
call Set_GF1_ByteRegister
;/* Wait a little while ... */
mov ecx,10
J57: call GF1_delay
loop J57
;/* Reset the MIDI port also */
mov edx,dword ptr midi_control
mov al,00000011b
out dx,al
mov ecx,10
J58: call GF1_delay
loop J58
xor al,al
out dx,al
;/* Clear all interrupts. */
mov al,41h ;DRAM DMA Control Register
mov cl,0
call Set_GF1_ByteRegister
mov al,045h ;Timer Control Register
mov cl,00h
call Set_GF1_ByteRegister
mov al,049h ;Sampling Control Register
mov cl,00h
call Set_GF1_ByteRegister
mov al,0Eh ; set active voices to 32
mov cl, 31 or 0C0h
call Set_GF1_ByteRegister
;/* Clear interrupts on voices. */
;/* Reading the status ports will clear the irqs. */
mov edx,dword ptr GF1_IRQ_status ; Read
in al,dx
mov al,041h ;DRAM DMA Control Register
call read_GF1_ByteRegister
mov al,049h ; Sampling Control Register
call read_GF1_ByteRegister
ClrFIFO:mov al,08Fh ;IRQ source Register
call read_GF1_ByteRegister
and al,11000000b
cmp al,11000000b ; keep on reading to clear IRQ's
jne ClrFIFO
mov BL,0
stop_loop:
outp GF1_Voice_Select,BL ; select voice to operate with
mov al,00h ; set Voice control
mov cl,00000010b ; (Stoped voice )
call Set_GF1_ByteRegister
mov al,0Dh ; set Volume Ramp control
mov cl,00000010b ; ( stoped ramping)
call Set_GF1_ByteRegister
mov al,09h ; Current Volume fully off
xor ecx,ecx
call Set_GF1_WordRegister
call GF1_delay ; /* Wait 4.8 micos. or more. */
inc bl
cmp bl,32
jb stop_loop
mov edx,dword ptr GF1_IRQ_status ; Read
in al,dx
mov al,041h ;DRAM DMA Control Register
call read_GF1_ByteRegister
mov al,049h ; Sampling Control Register
call read_GF1_ByteRegister
Cl2FIFO:mov al,08Fh ;IRQ source Register
call read_GF1_ByteRegister
and al,11000000b
cmp al,11000000b ; keep on reading to clear IRQ's
jne Cl2FIFO
mov al,0Eh ; set active voices to 14 again
mov cl, 13 or 0C0h
call Set_GF1_ByteRegister
;/* Set up GF1 Chip for interrupts & enable DACs. */
mov al,04Ch
mov cl,00000111b
call Set_GF1_ByteRegister
clc
popad
ret
Ultrasound_Init ENDP
;--------------------- end of ultrasound services ----------------------
; Some little procedures that are used by the Ultrasound services
read_GF1_ByteRegister proc
mov edx,dword ptr GF1_Reg_Select
out dx,al
add dl,2
in al,dx
ret
read_GF1_ByteRegister endp
Set_GF1_ByteRegister proc
mov edx,dword ptr GF1_Reg_Select
out dx,al
add dl,2
mov al,cl
out dx,al
ret
Set_GF1_ByteRegister endp
Set_GF1_WordRegister proc
mov edx,dword ptr GF1_Reg_Select
out dx,al
inc dl
mov eax,ecx
out dx,ax
ret
Set_GF1_WordRegister endp
;/***************************************************************
; * This function is used as a 1.6*3 microsecond (or longer) delay.
; * This is needed when trying to change any of the 'self-modifying
; * bits in the voice registers.
; ***************************************************************/
GF1_delay PROC
push edx
mov ah,7h
J55: mov dx,GF1_DRAM ; dummy port Read
in al,dx
dec ah
jnz J55
pop edx
ret
GF1_delay ENDP
;============================================================================
;
; Probe for an Ultrasound
;
; Expects DX = Ultrasound base port address
;
; Returns Carry clear if detected a GUS at this port address
; otherwise carry is set.
;
;============================================================================
Ultrasound_Probe PROC PASCAL USES ECX EDX EAX
cmp GUSdetected_flag, TRUE ; Don't detect if a GUS has aleady
je skip_detection ; been detected because some how
; I don't think too many pople are
; going to be unpluging thier GUS
; half way through a game.
mov GUS_Base_Port,DX
; Take the Ultrasound out of a reset state
add dx,103h ; because it's in a reset state at power up.
mov al,04Ch
out dx,al
add dl,2
mov al,00000111b
out dx,al
mov ecx,100h ; delay a bit ????
loop $
xor ecx,ecx ; Set location 0 to 055h
call UltraSetDRAM_address
mov al,055h
out dx,al
inc ecx ; Set location 1 to 0AAh
call UltraSetDRAM_address
mov al,0AAh
out dx,al
xor ecx,ecx ; Read location 0 and
call UltraSetDRAM_address ; compare it to 055h.
in al,dx
cmp al,055h
jne No_GUS_Found_here
mov GUSdetected_flag,True ; Set the GUS detected flag
;
; OK, there is a GUS. Time to initalize the port address varibles.
;
mov ax,GUS_Base_Port
mov ecx,offset The_Ultrasound_port_Addresses
PAdrLoop: add [ecx],ax
add ecx,2
cmp ecx,offset Ultrasound_ports_ends
jb PAdrLoop
skip_detection:
clc
ret
No_GUS_Found_here:
stc
ret
Ultrasound_Probe ENDP
;----------------------------------------------------------
; Procedure to set the DRAM I/O address of the Ultrasound
;
; Expects ECX with address
;
UltraSetDRAM_address PROC
mov DX,GUS_Base_Port
add dx,103h
mov al,043h ; DRAM I/O reg bits 0..15
out dx,al
inc dl
mov eax,ecx
out dx,ax
dec dl
mov al,044h ; DRAM I/O reg bits 16..19
out dx,al
add dl,2
shr eax,16
out dx,al
add dl,2 ; set DX to DRAM port
ret
UltraSetDRAM_address ENDP
;********************* END OF THE ULTRASOUND ROUTINES *********************
END