This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] CCS/TDA2EVM5777:DSP 上的内核移植

Guru**** 2927270 points
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/processors-group/processors/f/processors-forum/664941/ccs-tda2evm5777-kernel-porting-on-dsp

器件型号:TDA2EVM5777

工具/软件:Code Composer Studio

您好!

我们正在开发一个简单内核(Sobel)并在 DSP 上进行优化。 我们从 C66x Sobel 代码中获取了参考、但在处理后、我们无法获得预期结果。

有人可以帮助我在代码中找到问题吗?

谢谢

Vikase2e.ti.com/.../dsp_5F00_sobel_5F00_kernel.rar

附加项目以供参考

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    大家好、Vikas、

    我已将您的问题转发给 DSP 专家。

    此致、
    Yordabn
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    大家好、Vikas、


    请详细说明一下吗? 它将帮助我 更快地识别问题?

    此致、
    Shyam

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    大家好、Vikas、


    请详细说明一下吗? 它将帮助我 更快地识别问题?

    此致、
    Shyam

    Shyam、您好!
    如果您在"清醒边缘检测"中发现任何问题、请检查此代码。

    我还附加了从该代码接收的输出.........

    void eel_dsp_kernel_optimized (uint8_t * inPtr、uint8_t * outPtr、uint32_t width、uint32_t height)
    {
    
    uint8_t * inptr_a1[width]、* inptr_a2[width]、* inptr_a3[width];//处理数据的输入缓冲区
    uint8_t buffer[width];//输出缓冲区以处理数据
    uint8_t *temp1、*inptr1、*inptr2、*inptr3、*outpointer、 *指针;
    
    inpt1 =(uint8_t *) inptr_A1;
    inpt2 =(uint8_t *) inptr_A2;
    inpt3 =(uint8_t *) inptr_A3;
    
    inpointer = inPtr;
    outpointer = outPtr;
    //复制第一行
    memcpy (inptr1、inpointer、width);
    inpointer +=宽度;
    
    //复制第二行
    memcpy (inptr2、inpointer、width);
    inpointer +=宽度;
    
    //复制第三行
    memcpy (inptr3、inpointer、width);
    inpointer +=宽度;
    
    //将输入的第一行直接复制到输出缓冲区,因为我们不会处理第一行
    memcpy (outpointer、inptr1、width);
    outpointer +=宽度;
    
    int32_t x、y;
    int64_t mask1_8 = 0x0101010101010101;
    int64_t mask2_8 = 0x0202020202020202;
    uint32_t mask1_4 =_loll (mask1_8);
    uint32_t mask2_4 =_loll (mask2_8);
    int64_t r0、R1、R2、R01_lo、R01_hi、 r012_lo、r012_hi、r012_lo_D2、r012_hi_D2、C02_lo、 C02_hi;
    _x128_t r0_2、r1_2、r2_2;
    
    
    对于(y = 1;y <(height -1);y++)
    {
    uint32_t x0_3210 =_mem4_const (inpt1);
    uint32_t x1_3210 =_mem4_const (inpt2);
    uint32_t x2_3210 =_mem4_const (inpt3);
    
    /*将8bpp 转换为16bpp,以便我们可以对行进行 SIMD 加法*/
    int64_t x0_2 =_mpyu4ll (x0_3210、mask1_4);
    int64_t x1_2 =_mpyu4ll (x1_3210、mask2_4);
    int64_t x2_2 =_mpyu4ll (x2_3210、mask1_4);
    
    /*添加行0+1+2、逐列*/
    int32_t x01 =_ADD2 ((int32_t)_loll (x0_2)、(int32_t)_loll (x1_2));
    uint32_t xaxb =(uint32_t)_ADD2 (x01、(int32_t)_loll (x2_2));
    
    
    对于(x=0;x <(宽度/8);x++)
    {
    /*从3行中的每行读取8个字节。 *
    r0 =_mem8_const (&inpt1[(x*8)+ 2]);
    r1 =_mem8_const (&inpt2[(x*8)+ 2]);
    R2 =_mem8_const (&inpt3[(x*8)+ 2]);
    
    /*将8bpp 转换为16bpp,以便我们可以对行进行 SIMD 加法*/
    R0_2 =_dmpyu4 (r0、mask1_8);
    r1_2 =_dmpyu4 (r1、mask2_8);
    R2_2 =_dmpyu4 (R2、mask1_8);
    
    /*添加行0+1、按列*/
    r01_lo =_dadd2 (_lo128 (r0_2)、_lo128 (r1_2));
    R01_hi =_dadd2 (_hi128 (r0_2)、_hi128 (r1_2));
    
    /*将上一个总和添加到第2行、按列*/
    r012_lo =_dadd2 (R01_lo、_lo128 (R2_2));
    r012_hi =_dadd2 (R01_hi、_hi128 (R2_2));
    
    /*使用历史记录*/将此总和左移2个像素
    r012_lo_D2 =_itoll (_loll (r012_lo)、xaxb);
    r012_hi_d2 =_itoll (_loll (r012_hi)、_hill (r012_lo));
    
    C02_lo =_dsub2 (r012_lo、r012_lo_D2);
    C02_hi =_dsub2 (r012_hi、r012_hi_D2);
    
    /*为下一次迭代保存重叠数据*/
    xaxb =(uint32_t)_mVD ((int32_t)_hill (r012_hi));
    
    /*存储8个清晰的滤波器值*/
    _amem8 (&buffer[x*8]) = C02_lo;
    _amem8 (&buffer[(x*8)+4])= C02_hi;
    
    }
    
    memcpy (outpointer、buffer、width);
    outpointer +=宽度;
    
    //重新排列指针并再读取一行
    TEMP1 = inttr2;
    inptr2 = inptr3;
    inptr1 = temp1;
    
    //复制第三行
    memcpy (inptr3、inpointer、width);
    inpointer += width;
    }
    } 

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    大家好、Vikas、

    我还没有尝试过此代码、但乍一看、我在这里看到了一个潜在的问题、

        _amem8(&buffer[x*8])     = c02_lo;

        _amem8(&buffer[(x*8)+4]) = c02_hi;
    使用 amem8而不是 mem8时、需要确保地址与64位边界对齐。 看到在栈上分配了缓冲区[]、就不能保证它与64位边界对齐。 作为一个快速修复、您是否可以对商店使用 mem8而不是 amem8?
    此致、
    Shyam
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    Shyam、您好!
    这不起作用。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Vikas、

    我看了一下 main.c、它看起来就像您用 VXLIB_sobre x_3x3_i8u_o16s.c 作为参考、对吗?  如果是这样、此代码只会生成 int16_t 格式的 X 梯度、但假设输出指针为每像素8位、则会更新输出指针、因此这是一个问题。  您的 buffer[width]数组为8位、因此对其进行16位写入将使该缓冲区溢出2倍。  您可以看到、对于8个输入像素、正在写入16个输出字节。

    此外、您的参考 C 看起来像是同时生成 X 和 Y 梯度、并将它们组合成单个8位输出、而优化的代码没有这样做、因此这是另一个问题。  如果您同时需要 X 和 Y、我建议您参考 VXLIB_sobre _3x3_i8u_o16s_o16s 函数、该函数在单独的缓冲区中计算 X 和 Y 梯度。

    此致、

    Jesse

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    是的,我们从同一个文件中引用了这些边沿,并且我们只尝试在一个方向上找到这些边沿,这些边沿反映了代码本身的形式,您可以解决存储数据时出现的问题。 我们已在内部循环的末尾添加此代码、它开始提供正确的输出。

    int16_t pixel[8];
    _mem8 (像素[0]) = C02_lo;
    _mem8 (像素[0+4]) = C02_hi;

    对于(i=0;i<8;i++)

    像素[i]= abs (像素[i]);
    if (像素[i]>255)
    像素[i]= 255;
    Buffer[(x*8)+ i]=像素[i];


    使用内在函数替换这段代码的任何帮助。

    感谢您的支持。
    Vikas
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    Vikas、

    我尚未测试此代码、但您可以尝试这样的方法来消除循环并避免过多加载/存储到内存中。

    ================================================================================
    对于(i=0;i<8;i++)

    像素[i]= abs (像素[i]);
    if (像素[i]>255)
    像素[i]= 255;
    Buffer[(x*8)+ i]=像素[i];

    ================================================================================

    //复制削波值4次并存储在64位寄存器中
    uint32_t clip =(255 << 16)| 255;
    uint64_t clip_255k =_itoll (clip、clip);

    //加载8、16位值
    uint64_t pixel_0123 =_mem8 (&pixel[0]);
    uint64_t pixel_4567 =_mem8 (&pixel[0 + 4]);

    //一次计算2个16位值的绝对值
    uint32_t abs_01 =_abs2 (_loll (pixel_0123));
    uint32_t abs_23 =_abs2 (_hill (pixel_0123));
    uint32_t abs_45 =_abs2 (_loll (pixel_4567));
    uint32_t abs_67 =_abs2 (_hill (PIXEL _4567));

    //将它们打包成4组
    uint64_t abs_0123 =_itoll (abs_01、abs_23);
    uint64_t abs_4567 =_itoll (abs_45、abs_67);

    //检查值是否大于255
    uint32_t cmpg_0123 =_dcmpgt2 (abs_0123、clip_255k);
    uint32_t cmpg_4567 =_dcmpgt2 (abs_4567、clip_255k);

    //将结果位展开为掩码
    uint32_t mases_0123 =_dxpnd2 (cmpg_0123);
    uint32_t mases_4567 =_dxpnd2 (cmpg_4567);

    //使用掩码提取像素> 255的剪辑值
    uint32_t Result_0123 = CLIP_255k & MASK_0123;
    uint32_t retuls_4567 = clip_255k & mases_4567;

    //使用掩码提取像素值< 255
    uint32_t Result_0123 = Result_0123 |(abs_0123和~掩码_0123);
    uint32_t retuls_4567 = result_4567 |(abs_4567 &~遮罩_4567);

    //将结果存储在缓冲区中(假设缓冲区是16位缓冲区)
    mem8 (&buffer[0]) = RESULT_0123;
    _mem8 (&buffer[0 + 4])= result_4567;

    此外、这些文档将帮助您熟悉编程模型、内在函数和优化

    www.ti.com/.../spru198k.pdf - TMS320C6000编程人员指南
    www.ti.com/.../sprugh7.pdf - TMS320C6600 CPU 和指令集
    www.ti.com/.../sprabf2.pdf - TMS320C6000 DSP 优化简介
    www.ti.com/.../sprabg7.pdf -优化 C66x DSP 上的环路

    此致、
    Shyam
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    感谢 Shyam 花时间了解问题并提供适当的建议。

    我使用_davg2和_dmin2在更少的内在函数中转换了 c 代码

    //一次计算2个16位值的绝对值
    abs_01 =_abs2 (_loll (C02_lo));
    abs_23 =_abs2 (_hill (C02_lo));
    abs_45 =_abs2 (_loll (C02_hi));
    abs_67 =_abs2 (_hill (C02_hi));

    //将它们打包成4组
    C02_lo =_itoll (ABS_23,ABS_01 );
    C02_hi =_itoll (abs_67、abs_45);

    //取 x 方向和 y 方向边缘的平均值
    c012_lo =_davg2 (C02_lo、c012_lo);  其中 c012_lo 是 y 方向边沿
    c012_hi =_davg2 (C02_hi、c012_hi);  其中 c012 _hi 是 y 方向边缘

    //使用0xff 钳制值
    c012_lo =_dmin2 (c012_lo、min_value);
    c012_hi =_dmin2 (c012_hi、min_value);

    /*存储8个清晰的过滤值*/
    _mem8 (像素[0])     =  c012_lo;
    _mem8 (&PIXEL [0 + 4])  =  c012_hi;

    对于(i=0;i<8;i++)

    Buffer[(x*8)+ i]=像素[i];

    现在只剩下一件事,就是将 int64_t 变量中的数据存储在 uint8_t 数组中。

    谢谢

    Vikas

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    Vikas、

    由于每个 uint64_t 变量具有4个16位值、因此您可以使用 SPACKU4、它将执行饱和(255时)和打包结果(8位)。
    因此您可以避免使用 dmin2(...) 指令。

    此致、
    Shyam
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    是 Shyam、以下行将16位的结果转换为8位的结果并将结果饱和存储在8位数组中。

    mem4 (& buffer[(x*8)])      =   _spacku4 (_hill (c012_lo)、_loll (c012_lo));
    _mem4 (& buffer[(x*8)+4])   =  _spacku4 (_hill (c012_hi)、_loll (c012_hi));

    感谢您的支持。

    Vikas