;**************************************************************************
;  EG7.ASM
;
;  This example program does sends some stuff to/from the GUS via DMA.
;  Please note that this program requires the GUS.ASM and DMA.ASM library
;
; Written by Adam Seychell
;**************************************************************************
.386
.model  flat
.stack 200h

include  macros.386
include  dma.inc
include  gus.inc


GF1_clock               equ 617400

.DATA

DMA_buffer_phys         dD ?
DMA_buffer_addr         dD ?
DMA_DRAM_Address        dD ?
GUS_MEMORY              dD ?
DMAplay_Chan            dB ?
DMASamp_Chan            dB ?
DMAPlay_TC              dB ?
IRQ                     dB ?


.CODE

The_Start:        ;**************** ENTRY POINT OF THE PROGRAM ************



;********* Allocate a 16KB DMA buffer  ***************
        mov     ax,0EE41h
        int     31h
        jc  exit
        mov     DMA_buffer_addr,edx
        mov     DMA_buffer_phys,ebx




;********* Get the Default GUS settings from the "ULTRASND=" string *********

        Call    GetUltraConfig
        jnc Got_EnvString
            writeln 'Cannot find ''ULTRASND='' environment string or has invalid settings'
            mov     ax,4C00h
            int     21h

Got_EnvString:
        mov     DMAplay_Chan,CL                     ; save DMA channels
        mov     DMASamp_Chan,CH
        mov     IRQ,BL


;************  Fully reset the Ultraosund *************************
         call    Ultrasound_Reset           ; Expects DX=port
         jnc  got_ultra
            writeln 'Could not detect and Ultrasound on this computer '
            mov     ax,4C00h
            int     21h
got_ultra:

                                            ; Save memory installed
        mov     GUS_MEMORY,EDI


        writeln  'Filling Ultrasound''s DRAM via DMA ( # = 16Kb ).'



;************** Set the Ultrasounds IRQ vevctor *****************
        mov     edx,offset GUS_ISR
        mov     cx,cs                           ; CX:EDX = selectro:offset
        mov     bl,IRQ                          ; Convert IRQ to interrupt
        cmp     bl,8                            ; number
        jb Jpic1
        add     bl,60h
Jpic1:  add     bl,8
        mov     ax,0205h
        int     31h




; ****** program the 8237 DMA contoller  *************
        mov     al,01011000b             ; DMA mode register
        mov     ah,DMAPlay_Chan          ; Channel number ( 0..7 )
        mov     ecx,04000h               ; Bytes to transfer
        mov     ebx,DMA_buffer_PHYS      ; Physical base address
        call    DMA_setup                ; Do it ( see DMA.ASM )

; Note: Mode reg bit 4 is set for DMA auto initalizing mode.
; This means that the Address and Count registers don't have to be
;reprogramed after the DMA has finished transfering.


        mov     DMA_DRAM_Address,0


FILL_GUS_LOOP:
       ;********* Set the GUS's DMA DRAM staring address register *****

        mov     dx,GF1_Reg_select
        mov     al,042h                       ; Set DMA Start Address
        out     dx,al

        mov     eax,DMA_DRAM_address
        test    DMAPlay_chan,100b
        jz _8bitDMA
           ; ---- do 16 bit DMA address translation ( see the SDK ) -----
          mov     edi,eax
          shr     eax,1
          and     eax,01ffffh     ; zero out bit 17..19
          and     edi,0c0000h     ; get bits 18 and 19
          or      eax,edi
_8bitDMA:
        shr     eax,4
        mov     dx,GF1_data_LOW
        out     dx,ax                   ; Set the damn register

  ;********* Set the GF1 DMA Control Register  ****************

        mov     al,041h                ;Set DRAM  DMA Control Register
        mov     dx,GF1_Reg_Select
        out     dx,al

        mov     ah,DMAPlay_chan
        and     ah,100b
        mov     al,00100001b       ; Read, 650KB/s, 16bit data, 16/8bit DMA
        or      al,ah
        mov     dx,GF1_Data_HIGH
        out     dx,al

 ; The DMA cycle will now start





;********************** Wait around for the DMA to finish **************
               	mov     ecx,500000h
waitTC:        	test    DMAPlay_TC,1
                loopz  waitTC
                jz   timoutERROR
                mov     DMAPlay_TC,0


        mov     dl,'#'
        mov     ah,2
        int     21h

        add     DMA_DRAM_address,4000h
        mov     eax,GUS_MEMORY
        cmp     eax,DMA_DRAM_address
        ja FILL_GUS_LOOP

;************************* Stop DRAM  DMA cycle ********************
        mov     al,041h                ; Set DRAM DMA Control Register
        Mov     dx,GF1_reg_select
        out     dx,al

        mov     dx,GF1_data_HIGH
        mov     al,00000000b           ; stop IRQ's
        out     dx,al

        writeln


exit:

; ****** program the 8237 DMA contollers  *************
    ; Must turn of auto initalizing ????
    ;   Sometimes my computer goes to about 1/8th of it's speed
    ;   when if DMA auto initalizing bit is left on. Only a hardware reset
    ;   will make it go back to normal.

        mov     al,00001000b             ; DMA mode register
        mov     ah,DMAPlay_Chan          ; Channel number ( 0..7 )
        call    DMA_setup

; ****** Terminate Program  *************
        mov     ax,4C00h
        int     21h




timoutERROR:
        writeln 'ERROR:  got no IRQ form GUS'
        jmp exit







   ;******************** Gravis ultrasound IRQ handler ********************
GUS_ISR  PROC
        push    ds                              ; Save all registers used
        pushad

        mov     ax,_TEXT                        ; Load DS with data selector
        mov     ds,ax

 ;
 ; First determine if IRQ was form DMA Terminal Count or it was
 ; from one of the Voices. Note: we should never get an IRQ from
 ; a Voice since none of the GF1 voices registers have been programmed.
 ; Only the DRAM DMA IRQ thingy has been programmed.

        mov     dx,GF1_IRQ_status
        in      al,dx
        test    al,10000000b             ; look for a DMA TC IRQ
        jnz was_DMA_TC

     ;
     ; Must read the IRQ source register to clear the FIFO interrupts
     ;
   	     mov     dx,GF1_REG_Select
             mov     al,08fh
             out     dx,al
             mov     dx,GF1_DATA_High
             in      al,dx
             jmp  exit_ISR



was_DMA_TC:
    ;
    ;  Read DRAM DMA controll register to allow more DRAM DMA IRQs.
    ;   Reading this register will clear the IRQ pending bit so
    ;   another DRAM DMA IRQ can occurr.

        mov     dx,GF1_REG_Select
        mov     al,041h             ; DRAM  DMA Control Register
        out     dx,al
        mov     dx,GF1_DATA_High    ; read
        in      al,dx
        or      DMAPlay_TC,1


exit_ISR:
        mov     al,020h                 ; EOI to both PICs (8259)
        out     20h,al
        out     0A0h,al
        popad
        pop     ds
        iretd

GUS_ISR ENDP
;******************** End of Gravis ultrasound IRQ handler ******************






END The_Start
