| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 | 
| André Goddard Rosa | af901ca | 2009-11-14 13:09:05 -0200 | [diff] [blame] | 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.  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 |  | 
 | 55 | struct 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 | 
 | 77 | void 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 | } |