DSP

TMS320c64x+ DSP IDMA 控制器

2019-07-13 16:15发布

    IDMA控制器的目的是实现任何两个内部内存之间数据块的快速搬移,包括一级程序内存(L1P)、一级数据内存(L1D)以及二级内存(L2),或外部外设配置内存(即向外设配置寄存器写值)。但IDMA不能向内部MMR搬入数据,也不能从MMR搬出数据。IDMA的优势还是在于能够在较慢的L2和较快的L1(包括L1P & L1D)之间快速搬移数据。相对于cache,它的延时更少,因为IDMA在后台运行。另外,IDMA还可以通过外部配置空间(CFG)端口迅速对外设配置寄存器编程,但注意,不能源和目的都是CFG,没有CFG到CFG的传输,并且CFG只能用channel 0访问,这点通过后面IDMA的几个控制寄存器可以看出。       IDMA控制器包含两个通道:channel 0 & channel 1。这两个通道相互正交,允许同时操作。IDMA的操作通过以下通道和几个寄存器来控制。 1. IDMA channel 0:
    首先区分external configuration space & internal configuration space。前者指核之外设备的寄存器,后者指核内部设备的寄存器,我们通常接触的都是后者,如L1D等的配置寄存器,后者只能通过CPU使用load/store指令来访问; IDMA channel 0只能访问前者,并且每次固定访问32-word块,由5个寄存器控制。
    IDMA channel 0的源和目的地址必须32-byte对齐,一次可以配置32-word块大小的寄存器,但使用mask register,可以选择性只配置其中某些寄存器,mask为1,表示对应word不传输。CPU按顺序连续递增的写通道的各寄存器才可以,就自动触发通道传输了。对channel 0,CPU写寄存器的顺序必须是:MASK-SOURCE-DEST -COUNT,写完COUNT后,就触发传输了。对每个IDMA通道,可以在任何时候触发传输,而且,任何时候每个通道允许存在两个传输(一个active,一个pending),但只有激活的传输结束后才会启动下一个传输。如下:
    IDMA0_MASK       = ox00000F0F;
    IDMA0_SOURCE = MMR_ADDRESS;
    IDMA0_DEST       = reg_ptr;
    IDMA0_COUNT    = 0;
    while (IDMA0_STATUS);    //++等待传输完毕
    //++++更新寄存器值,准备下一次传输++++
    IDMA0_MASK      = ox00000F0F;
    IDMA0_SOURCE = reg_ptr
    IDMA0_DEST      = MMR_ADDRESS;;
    IDMA0_COUNT    = 0;   
    又如,用IDMA channel 0递交多个QDMA请求的例子,每个QDMA有8-word参数entry,一次IDMA传输32-word块,故一次IDMA传输可以配置4个QDMA通道参数:
    IDMA0_MASK      = ox4F4F4F4F;    //++屏蔽每个QDMA参数entry的0,1,2,3,6,即只修改4,5,7
    IDMA0_SOURCE = &qdma_list[0]; //++参数配置列表
    IDMA0_DEST      = &QDMA[0];        //++查表获得QDMA首地址
    IDMA0_COUNT   = 1;                    //++两次,每次32-word,共配置8个QDMA通道
    while (IDMA0_STATUS);   
2. IDMA channel 1:
    用于在local memory之间传递数据或程序段,后台运行,无需CPU操作。channel 1有4个配置寄存器:status,source,dest,count.同channel 0一样,CPU顺序写完COUNT寄存器后自动启动传输,同样允许存在两个传输(一个active,一个pending),但只有激活的传输结束后才会启动下一个传输,下面伪代码使用IDMA完成数据在L1D & L2之间的page in/out,采用了乒乓操作,可以借鉴:
    IDMA1_SOURCE = outBuffFastA;                 //++源地址(L1D)
    IDMA1_DEST       = &outBuff[n-1];                  //++目的地址(L2)
    IDMA1_COUNT    = 7<                                       0<                                       buffsize;                             //++set count to buffer size (in byte)
    //++page in input buffer n+1 to fast memory++
    IDMA1_SOURCE = inBuffer[n+1];
    IDMA1_DEST       = inBuffFastA;;
    IDMA1_COUNT    = 7<                                      1<                                       buffsize;
    ...process input buffer n in Pong --inBufferFastB -> outBuffFastB...
    另外,还可以使用IDMA channel 1向某一块local mem填充特定的值。将IDMA1_COUNT->FILL设为1,当它为1,IDMA1源地址为填充值,填充目的地是目的地址指向的memory buffer,IDMA1_COUNT->COUNT决定copy的次数。 3. 寄存器说明
   >IDMA0_STAT是只读寄存器;
   >IDMA0_MASK屏蔽32-word中不需要修改的word参数;
   >IDMA0_SOURCE低5-bit为reserved,仅高27-bit有效,必须是local memory地址:L1P,L1D,L2或CFG,必须32-byte对齐,而且源和目的不可同为CFG;
   >IDMA0_DEST低5-bit为reserved,仅高27-bit有效,必须是local memory地址:L1P,L1D,L2或CFG,必须32-byte对齐,而且源和目的不可同为CFG;
   >IDMA0_COUNT指定当次传输中需传的32-word block的个数,4-bit COUNT域最大值为15,表示最多允许连续传输16个block。MASK域值对每个block都有效。所有block都是物理连续的32-word区域,源和目的地址递增。IDMA0_COUNT->INT域为真,表示允许产生CPU中断,通知CPU传输结束。
   >IDMA1_STAT是只读寄存器;
   >IDMA1_SOURCE做传输时必须是local mem地址:L1P,L1D,L2或CFG,源地址与目的地址必须是不同的端口(L2 port0 & L2 port1认为是同一端口,即不能L2传到L2),这样才可以获得256-bit/EMC cycle(32-byte/cycle)的最佳速度。如果当前执行的是填充fill操作而非数据传输操作,SOURCE中放的不是地址,而是填充值,IDMA将该值copy到整个目标buffer.
   >IDMA1_DEST寄存器低[1 0]bit为reserved,仅高30-bit有效.必须是local mem地址:L1P,L1D,L2或CFG,源地址与目的地址必须是不同的端口(L2 port0 & L2 port1认为是同一端口,即不能L2传到L2),这样才可以获得256-bit/EMC cycle(32-byte/cycle)的最佳速度。
   >IDMA1_COUNT->COUNT域指定传输长度,以byte为单位,必须4-byte的倍数。IDMA1_COUNT->INT域为真,表示允许产生CPU中断,通知CPU传输结束,如果COUNT为了,即并没有实际数据传输,如果INT为真,仍然会产生一个中断,通知CPU可以做随后的处理;IDMA1_COUNT->PRI[31 29]指定优先级,当传输与CPU或DMA访问发生冲突时做仲裁用,可以为0~7(低)任何值;IDMA1_COUNT->FILL域指明当前操作为值填充还是数据搬移。
      对达芬奇平台来说,感觉IDMA好像并不那么实用,首先,需要同时配置多个外部寄存器,如QDMA的情况并不多;其次,IDMA的一个主要功能是实现local mem之间的数据、代码搬移,可是达芬奇L2仅有64K,就算全部配置成SRAM,空间也是有限的,能够允许在此过渡的数据量也很有限,很奇怪的是为何不直接用QDMA,直接在DDR于L1之间交互?IDMA在编码器开发中到底有多大作用,还需要验证。