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<<IDMA_PRI_SHIFT | //++set priority to low
0<<IDMA_INT_SHIFT | //++do not interrupt cpu
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<<IDMA_PRI_SHIFT |
1<<IDMA_INT_SHIFT |
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在编码器开发中到底有多大作用,还需要验证。