home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / assemblr / library / sound / sb_dma / dma_code.asm next >
Assembly Source File  |  1992-03-12  |  8KB  |  238 lines

  1.                 IDEAL
  2.                 MODEL small
  3.  
  4. ;---------------------------------------------------------------------------
  5. ;  IBM-PC(tm) compatible programmer's DMA library
  6. ;  Version 1.0
  7. ;---------------------------------------------------------------------------
  8. ;  Copyright (C) 1992, Heath I Hunnicutt
  9. ;  Portions Copyright (C) 1986, Carnegie Mellon University
  10. ;---------------------------------------------------------------------------
  11. ;  Thanks to: Gary Nemirovsky
  12. ;---------------------------------------------------------------------------
  13. ;  This document is for free public distribution.  It is unlawful to
  14. ;  sell this document, or any work based substantially upon it.
  15. ;---------------------------------------------------------------------------
  16. ;  This assembly code defines 3 functions that are intended for use
  17. ;  by C programmers in code that requires access to the DMA system.
  18. ;
  19. ;  DMA transfers occur asynchronously to the CPU's activity, so they
  20. ;  are quite efficient.
  21. ;
  22. ;  The general sequence for using the DMA is:
  23. ;      int channel=1;   /* DO NOT use channel 0 */
  24. ;      dma_reset(channel);
  25. ;      dma_setup(channel,(char far *)My_Buffer,sizeof(My_Buffer),1);
  26. ;      /* Insert "foreground" code here. */
  27. ;      while (dma_done!=-1)
  28. ;         ;
  29. ;---------------------------------------------------------------------------
  30. ; Caution: There is some weird bug in dma_setup that causes crashes
  31. ;          if the length is greater than approx. 32000.
  32. ;          There doesn't seem to be any 'magic-number' like 32768
  33. ;          that relates to this.
  34. ;---------------------------------------------------------------------------
  35. ; Send suggestions, questions, comments, knoweledge to:
  36. ;          heathh@cco.caltech.edu     (also @tybalt.cco.caltech.edu)
  37. ;          (or hihunn@through.ugcs.caltech.edu  -- not preferred)
  38. ;---------------------------------------------------------------------------
  39. ; PUBLIC FUNCTIONS
  40. ;    void far dma_reset(int Channel)
  41. ;    void far dma_setup(int Channel,char far *Buffer,int Length,int Dir)
  42. ;    int  far dma_done(int Channel)
  43. ;---------------------------------------------------------------------------
  44. ; How to assemble this code:
  45. ;      You'll need Turbo Assembler(tm) from Borland(tm) Internationl
  46. ; TASM /mx /m2 dma_code
  47. ;---------------------------------------------------------------------------
  48.  
  49.  
  50. byte_ptr           EQU    00ch    ; byte pointer flip-flop
  51. mode               EQU    00bh    ; dma controller mode register
  52. dma_mask           EQU    00ah    ; dma controller mask register
  53.  
  54. addr               EQU    000h    ; per-channel base address
  55. count               EQU    001h    ; per-channel byte count
  56.  
  57. read_cmd           EQU    048h    ; read mode
  58. write_cmd          EQU        044h    ; write mode
  59. set_cmd               EQU    000h    ; mask set
  60. reset_cmd          EQU    004h    ; mask reset
  61.  
  62. ; dma controller page register table
  63. ; this table maps from channel number to the i/o port number of the
  64. ; page register for that channel
  65.                 DATASEG
  66.  
  67. page_table         DW    00087h    ; channel 0
  68.                DW    00083h    ; channel 1
  69.                DW    00081h    ; channel 2
  70.                  DW    00082h    ; channel 3
  71.  
  72.                 CODESEG
  73. MACRO zero reg
  74.       xor reg,reg
  75. ENDM zero
  76.       
  77. PUBLIC _dma_setup,_dma_reset,_dma_done
  78. ; --------------------------------------------------------------------------
  79. ;  void far dma_setup(int Channel,char far *Buffer,int Length,int Dir)
  80. ;--------------------------------------------------------------------------
  81. ;  Channel = 0-3  !Channel 0 is often reserved for memory refresh!
  82. ;  Buffer  = Address of data to play
  83. ;  Length  = Length of data to play
  84. ;          NOTE: For some reason, certain combinations of Buffer and
  85. ;                Length cause the system to lock up.  As a rule,
  86. ;                keep the Length < 30000 (dec), and DO NOT try to play
  87. ;                any region of memory that might be simultaneously
  88. ;                accessed, such as shared memory, code segments
  89. ;                including the ROM and TSRs that hook interrupts, etc.,
  90. ;  Dir     = Direction to move bytes.  1 == Out to the BUS (TO the card)
  91. ;                                      0 == In from the BUS and cards.
  92. ;---------------------------------------------------------------------------
  93. PROC _dma_setup FAR
  94. ARG Channel:WORD,Buffer:DWORD,Len:WORD,Dir:WORD
  95.     push bp
  96.     mov  bp,sp
  97.         push ax bx cx dx si di
  98.     pushf
  99.  
  100. ;Convert seg:ofs Buffer to 20-bit physical address
  101. ;Assumes operating in 8086/real-mode
  102.         mov  bx,[WORD PTR Buffer]
  103.         mov  ax,[WORD PTR Buffer+2]
  104.     mov  cl,4
  105.         rol  ax,cl
  106.         mov  ch,al
  107.         and  al,0F0h
  108.         add  ax,bx
  109.         adc  ch,0
  110.         and  ch,0Fh
  111.         mov  di,ax
  112. ; (ch << 16) + di == The physical buffer base.
  113.  
  114. ;Calculate the port to receive this address
  115.         mov  bx,[Channel]
  116.         shl  bx,1
  117. ;bx == Port # Channel*2
  118.  
  119. ;Determine which command byte will be written later
  120.         cmp  [WORD PTR Dir],0
  121.          jnz SHORT @@Do_Read
  122.         mov  al,write_cmd
  123.          jmp SHORT @@Do_Mode
  124. @@Do_Read:
  125.       mov  al,read_cmd
  126. @@Do_Mode:
  127.         mov  cx,[Channel]
  128.       add  al,cl
  129.         zero ah
  130.         mov  si,ax
  131.         mov  ax,set_cmd
  132.         add  al,cl
  133.         mov  cl,al
  134. ;si contains READ/WRITE command for DMA controller
  135. ;cl contains confirmation command for DMA controller
  136.  
  137. ;-------------------------------------------------------------------------
  138. ; Calculations have been done ahead of time to minimize time with
  139. ; interrupts disabled.
  140. ;
  141. ; ch:di == physical base address
  142. ;
  143. ; cl == Confirmation command    (Tells DMA we're done bothering it.)
  144. ;
  145. ; bx == I/O port Channel*2      (This is where the address is written)
  146. ;
  147. ; si == Mode command for DMA
  148. ;-------------------------------------------------------------------------
  149.      cli                     ;Disable interrupts while mucking with DMA
  150.  
  151. ;I have no idea what purpose these next three instructions serve.
  152. ;Without them, the procedure crashes and burns.
  153.         mov  al,0
  154.     mov  dx,byte_ptr    ; reset the byte pointer to be safe
  155.     out  dx,al
  156.  
  157.         mov  ax,di              ;ax=LSW of 20-bit address
  158.         mov  dx,bx
  159.     out  dx,al              ;Store LSB
  160.         mov  al,ah
  161.         out  dx,al              ;Store next byte
  162.  
  163.         mov  al,ch
  164.         mov  dx,[bx + OFFSET page_table]        ;Port is the "Page index"
  165.         out  dx,al              ;Store the page
  166.  
  167. ;Write length to port Channel*2 + 1
  168.         mov  ax,[Len]
  169.         mov  dx,bx
  170.         add  dx,count
  171.         out  dx,al              ;Write LSB
  172.         mov  al,ah
  173.         out  dx,al              ;Write MSB
  174.  
  175.         mov  ax,si              ;Load pre-calculated command
  176.         mov  dx,mode
  177.         out  dx,al              ;Write it to the DSP
  178.  
  179.     mov  dx,dma_mask
  180.         mov  al,cl
  181.         out  dx,al
  182.  
  183.         popf
  184.         pop  di si dx cx bx ax
  185.         pop  bp
  186.         ret
  187. ENDP _dma_setup                    
  188.  
  189. ;---------------------------------------------------------------------------
  190. ;  void far dma_reset(int Channel)
  191. ;---------------------------------------------------------------------------
  192. ;  Channel = 0-4
  193. ;          Resets the specified channel.
  194. ;          NOTE: It is a very bad idea to reset channel 0.
  195. ;---------------------------------------------------------------------------
  196. PROC _dma_reset FAR
  197. ARG Channel:Word
  198.     push bp
  199.         mov  bp,sp
  200.         push ax dx
  201.         mov  dx,dma_mask
  202.         mov  ax,reset_cmd
  203.         add  ax,[Channel]
  204.         out  dx,al
  205.         pop  dx ax
  206.         pop  bp
  207.         ret
  208. ENDP _dma_reset
  209.  
  210. ;---------------------------------------------------------------------------
  211. ;  int far dma_done(Channel)
  212. ;---------------------------------------------------------------------------
  213. ;  Channel = 0-4
  214. ;---------------------------------------------------------------------------
  215. ;  Returns: -1 if DMA transaction completed
  216. ;          (Maybe it returns the number of bytes left to transfer?)
  217. ;---------------------------------------------------------------------------
  218. PROC _dma_done FAR
  219. ARG Channel:Word
  220.     push bp
  221.         mov  bp,sp
  222.         pushf
  223.         push dx
  224.         mov  dx,[Channel]
  225.         shl  dx,1
  226.         add  dx,count
  227.         cli
  228.         in   al,dx
  229.         mov  ah,al
  230.         in   al,dx
  231.         xchg al,ah
  232.         pop  dx
  233.         popf
  234.         pop  bp
  235.         ret
  236. ENDP _dma_done
  237. END
  238.