DSP汇编中的循环问题

2019-03-26 16:36发布

  我的板子是c6740,编写测试程序想把两个数组对应的数相乘存到第三个数组中,主文件是:
#include <stdio.h> int MPY_1(int *m, int *n, int *result, int count); void main()
{
 int n[10] = {1,2,3,4,5,6,7,8,9,10};
 int m[10] = {11,12,13,14,15,16,17,18,19,20};
 int tmp,i;
 int *result;
 result = (int *)malloc(10*sizeof(int));
 tmp = MPY_1(m,n,result,10);
 for(i=0;i<10;i++)
  printf("m=%d,n=%d,result=%d,d=%d ",m,n,result,tmp); }
/**************调用汇编函数文件****************/
 .text
 .global _MPY_1
_MPY_1:     .asg A4, p_m
  .asg B4, p_n
  .asg A6, p_result
  .asg B6, B_count
  .asg A1, A_m
  .asg B1, B_n
  .asg A3, A_loopcount
  .asg A7, A_s
* ================= LOOP PROLOG ============================ *
   MV .S1 B6, A_loopcount    || MV .L1 A4,B4   || MV .L2 A5,B5
 SUB .S1 A_loopcount, 1,A_loopcount
* ===================== LOOP KERNEL ============================== *
loop:
    LDW .D1 *A5++[1], A_m ;A_m = *m
  ||  LDW .D2 *B5++[1], B_n ;A_n = *n
   MPY .M1 A_m,B_n,A_s ; A_S = m * n 
    NOP 1
 STW .D1 A_s,*A6++[1]  ; result = A_S
  
 ||[A_loopcount] B .S2 loop    ; branch ,Illegal register for conditional
    ||[A_loopcount]SUB .S1 A_loopcount, 1,A_loopcount
 
* ===================== LOOP EPILOG ============================== *
 B .S2 B3   ;return
 MVK .S1 1,A4 ;return 1
 nop 1
 .end   这程序编译没通过,在||[A_loopcount] B .S2 loop   这条语句下报错Illegal register for conditional。
第一次写汇编循环,请大侠帮看下这个程序哪些地方出错了?需要怎么改才能实现所想要的功能,谢谢! [ 本帖最后由 breeze505 于 2012-4-27 14:35 编辑 ] 此帖出自小平头技术问答
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
18条回答
carrotchen
1楼-- · 2019-03-26 23:55
 精彩回答 2  元偷偷看……
breeze505
2楼-- · 2019-03-27 04:09
< 非常感谢,经过你的指导,我添加了4个NOP来等待跳转,代码OK了,但感觉这样程序中NOP很多,效率不高,我的代码如下:
.text
        .global _MPY_1
_MPY_1:
                .asg A6, p_result
                .asg B6, B_count
                .asg A7, A_m
                .asg B7, B_n
                .asg A1, A_loopcount
                .asg A8, A_s
* ================= LOOP PROLOG ============================ *
          MV .S1 B6, A_loopcount       
* ===================== LOOP KERNEL ============================== *
loop:
           LDW .D1T1 *A4++[1], A_m ;A_m = *m
        ||LDW .D2T2 *B4++[1], B_n ;A_n = *n
    NOP 5
          MPY .M1X A_m,B_n,A_s ; A_S = m * n       
           NOP 1
   SUB .S1 A_loopcount, 1,A_loopcount       
  ||STW .D1 A_s,*p_result++[1]  ; result = A_S               
  ||[A_loopcount] B .S2 loop
  NOP 5
       
* ===================== LOOP EPILOG ============================== *
        B .S2 B3   ;return
        MVK .S1 1,A4 ;return 1
        nop 1
        .end

现在C接口做如下改变:
typedef unsigned char BYTE;
int MPY_1( BYTE*m, BYTE*n, BYTE*result, int count);
我的目的是:因为乘法器16*16是最快的,那我们是否可以把传入的BYTE数组一次读取两个元素,这样循环只需要进行5次就够了,但不知道怎么一次操作两个元素。可以帮忙指导下吗?就如上面那个代码里需要做上面修改呢?
zczc
3楼-- · 2019-03-27 05:01
很好
carrotchen
4楼-- · 2019-03-27 08:33
1. 你的代码的循环体比较少,采用指令重排只能节省一两条指令,所以优化的意义并不明显。
LDW .D1T1 *A4++[1], A_m ;A_m = *m
||LDW .D2T2 *B4++[1], B_n ;A_n = *n
NOP 5
MPY .M1X A_m,B_n,A_s ; A_S = m * n       
NOP 1
SUB .S1 A_loopcount, 1,A_loopcount ; -------> 提到MPY之前
||STW .D1 A_s,*p_result++[1] ; result = A_S
||[A_loopcount] B .S2 loop ; -------> 也提到MPY之前,并根据Delay slot重新设置LDW之后的NOP值
NOP 5

2. 乘数BYTE*m, BYTE*n,是存成8位还是16位的数?
如果是8位,m n不都是有符号数,循环次数又是4的整数倍,可以用MPYSU4, MPYU4, MPYUS4指令,需3个Delay Slot;数组必须4字节对齐,用LDW指令一次读取4个byte

如果是16位数,数组须4字节对齐,用LDW指令一次读取2个short,分别用MPY和MPYH计算低16位、高16位的乘积结果;也可以MPY2指令,需3个delay slot

3. 乘积结果是BYTE *r,这个有疑问。一般情况下8位乘8位的结果需用16位保存,16位乘16位的结果需用32位保存,否则就会溢出,除非你能很明确,乘数的值小于16 (以8位无符号数为例)。
breeze505
5楼-- · 2019-03-27 08:44
感谢你的指导,给了我实现的方向。
我最终的目的是要高效的汇编实现一幅64*64像素的RGB-YCbCr转换,其C代码主体我采用的是位移运算,如下:
void Rgb2YCbCr(const BYTE* pSrcRGB, short BytesPerRow, BYTE *pYBuffer, BYTE *pCbBuffer, BYTE *pCrBuffer, int BlockWidth, int BlockHeight)
{.....
y = ((r >> 2) + (r >> 5) + (r >> 6))  + ((g >> 1) + (g >> 4) + (g >> 6) + (g >> 7))    + ((b >> 4) + (b >> 5) + (b >> 6));
cb = 128 - ((r >> 3) + (r >> 5) + (r >> 7)) - ((g >> 2) + (g >> 4) + (g >> 6)) + (b >> 1) ;
cr = (r >> 1) - ((g >> 2) + (g >> 3) + (g >> 5) + (g >> 7)) - ((b >> 4) + (b >> 6)) + 128;
y = between(y, 0, 255);//因为经过上面的运算,Y有可能操作255值
...
}
////////////////////////////////////////////回到汇编讨论
(1)数组肯定是4字节对齐的,如果一次操作4组数据,读可以用LDW指令,加法可以用ADD4指令,但是无对应的位移操作指令,而且ADD4加法运算会超出255,令数据丢失。
(2)所以,我想最多一次只能操作2组数据吧?那这样的话,可以用哪些指令实现一次读2个数组同时操作,而又不会出现数据丢失?
(3)刚想到一个问题,RGB是连续存放的,那用LDW指令一次读取4个数据中R、G、B都有,这样乱了,所以,如果这样的话,我是否一定需要在主程序中就先把R、G、B分开成3个数组?这样才能在汇编中一次操作多组数据
breeze505
6楼-- · 2019-03-27 10:51
 精彩回答 2  元偷偷看……

一周热门 更多>