linux/sound/pci/cs46xx/imgs/cwcdma.asp
<<
>>
Prefs
   1// 
   2//  Copyright(c) by Benny Sjostrand (benny@hostmobility.com)
   3//
   4//  This program is free software; you can redistribute it and/or modify
   5//  it under the terms of the GNU General Public License as published by
   6//  the Free Software Foundation; either version 2 of the License, or
   7//  (at your option) any later version.
   8//
   9//  This program is distributed in the hope that it will be useful,
  10//  but WITHOUT ANY WARRANTY; without even the implied warranty of
  11//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12//  GNU General Public License for more details.
  13//
  14//  You should have received a copy of the GNU General Public License
  15//  along with this program; if not, write to the Free Software
  16//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  17//
  18
  19
  20//
  21// This code runs inside the DSP (cs4610, cs4612, cs4624, or cs4630),
  22// to compile it you need a tool named SPASM 3.0 and DSP code owned by 
  23// Cirrus Logic(R). The SPASM program will generate a object file (cwcdma.osp),
  24// the "ospparser"  tool will genereate the cwcdma.h file it's included from
  25// the cs46xx_lib.c file.
  26//
  27//
  28// The purpose of this code is very simple: make it possible to tranfser
  29// the samples 'as they are' with no alteration from a PCMreader
  30// SCB (DMA from host) to any other SCB. This is useful for AC3 through SPDIF.
  31// SRC (source rate converters) task always alters the samples in somehow,
  32// however it's from 48khz -> 48khz.
  33// The alterations are not audible, but AC3 wont work. 
  34//
  35//        ...
  36//         |
  37// +---------------+
  38// | AsynchFGTxSCB |
  39// +---------------+
  40//        |
  41//    subListPtr
  42//        |
  43// +--------------+
  44// |   DMAReader  |
  45// +--------------+
  46//        |
  47//    subListPtr
  48//        |
  49// +-------------+
  50// | PCMReader   |
  51// +-------------+
  52// (DMA from host)
  53//
  54
  55struct dmaSCB
  56  {
  57    long  dma_reserved1[3];
  58
  59    short dma_reserved2:dma_outBufPtr;
  60
  61    short dma_unused1:dma_unused2;
  62
  63    long  dma_reserved3[4];
  64
  65    short dma_subListPtr:dma_nextSCB;
  66    short dma_SPBptr:dma_entryPoint;
  67
  68    long  dma_strmRsConfig;
  69    long  dma_strmBufPtr;
  70
  71    long  dma_reserved4;
  72
  73    VolumeControl s2m_volume;
  74  };
  75
  76#export DMAReader
  77void DMAReader()
  78{
  79  execChild();
  80  r2 = r0->dma_subListPtr;
  81  r1 = r0->nextSCB;
  82        
  83  rsConfig01 = r2->strmRsConfig;
  84  // Load rsConfig for input buffer
  85
  86  rsDMA01 = r2->basicReq.daw,       ,                   tb = Z(0 - rf);
  87  // Load rsDMA in case input buffer is a DMA buffer    Test to see if there is any data to transfer
  88
  89  if (tb) goto execSibling_2ind1 after {
  90      r5 = rf + (-1);
  91      r6 = r1->dma_entryPoint;           // r6 = entry point of sibling task
  92      r1 = r1->dma_SPBptr,               // r1 = pointer to sibling task's SPB
  93          ,   ind = r6;                  // Load entry point of sibling task
  94  }
  95
  96  rsConfig23 = r0->dma_strmRsConfig;
  97  // Load rsConfig for output buffer (never a DMA buffer)
  98
  99  r4 = r0->dma_outBufPtr;
 100
 101  rsa0 = r2->strmBufPtr;
 102  // rsa0 = input buffer pointer                        
 103
 104  for (i = r5; i >= 0; --i)
 105    after {
 106      rsa2 = r4;
 107      // rsa2 = output buffer pointer
 108
 109      nop;
 110      nop;
 111    }
 112  //*****************************
 113  // TODO: cycles to this point *
 114  //*****************************
 115    {
 116      acc0 =  (rsd0 = *rsa0++1);
 117      // get sample
 118
 119      nop;  // Those "nop"'s are really uggly, but there's
 120      nop;  // something with DSP's pipelines which I don't
 121      nop;  // understand, resulting this code to fail without
 122            // having those "nop"'s (Benny)
 123
 124      rsa0?reqDMA = r2;
 125      // Trigger DMA transfer on input stream, 
 126      // if needed to replenish input buffer
 127
 128      nop;
 129      // Yet another magic "nop" to make stuff work
 130
 131      ,,r98 = acc0 $+>> 0;
 132      // store sample in ALU
 133
 134      nop;
 135      // latency on load register.
 136      // (this one is understandable)
 137
 138      *rsa2++1 = r98;
 139      // store sample in output buffer
 140
 141      nop; // The same story
 142      nop; // as above again ...
 143      nop;
 144    }
 145  // TODO: cycles per loop iteration
 146
 147  r2->strmBufPtr = rsa0,,   ;
 148  // Update the modified buffer pointers
 149
 150  r4 = rsa2;
 151  // Load output pointer position into r4
 152
 153  r2 = r0->nextSCB;
 154  // Sibling task
 155
 156  goto execSibling_2ind1 // takes 6 cycles
 157    after {
 158      r98 = r2->thisSPB:entryPoint;
 159      // Load child routine entry and data address 
 160
 161      r1 = r9;
 162      // r9 is r2->thisSPB
 163
 164      r0->dma_outBufPtr = r4,,
 165      // Store updated output buffer pointer
 166
 167      ind = r8;
 168      // r8 is r2->entryPoint
 169    }
 170}
 171