RISC-V MCU中文社区

【分享】 E203_NICE软件demo_nice源码解读

发表于 全国大学生集成电路创新创业大赛 2021-06-17 01:16:03
3
4799
14

大家好,我们是集创赛 CICC1061 好家伙队,本帖我们将结合芯来科技官方提供的nice_demo例程,进行嵌入式软件源码的讲解介绍。由于笔者本人也是刚刚开始学习嵌入式开发的萌新,全文难免有一些疏漏之处,还请大佬不吝赐教,在评论区直接指出文中的错误!


本次分享主要介绍nice_demo例程的软件源码部分,附nice_demo的下载地址:GitHub链接




1.网页如图所示,点击上图网页右侧的下载按钮,将完整的软件例程下载到自己的电脑上。





2.在下载得到的文件夹中,进入…………\nuclei-board-labs-master\e203_hbirdv2\common路径,即可找到nice_demo源码文件夹

进入文件夹,我们可以看到项目共由三个文件构成:

其中demo_nice.c文件是主程序,insn.c是定义计算函数的文件,insn.h是定义协处理器内联汇编指令的文件。






3.我们顺藤摸瓜,从主程序demo_nice.c看起:


这是主程序的开始位置,这一部分用C语言定义了一个二维数组array作为数据输入。

紧接着,代码原作者想要用一种对比的方式凸显NICE协处理器对矩阵运算的加速作用,因此原作者分别使用了纯软件(纯C语言代码)的方式使用协处理器硬件加速的方式来完成这个计算二维数组行列和的任务。如下图展示的代码所示:

左图是使用纯软件方式计算二维数组的行列和,右图是通过协处理器指令计算行列和。在调用计算行列和的函数   normal_case(array)  和     nice_case(array)  的前后分别使用  __get_rv_instret()  和  __get_rv_cycle()  获取当前的已经完成的指令计数器的值和当前CPU时钟计数器的值,以便于前后作差求得完成所需任务消耗的指令数和时钟周期数,用于对比协处理器的硬件加速效率。







4.接下来我们来看看在insn.c文件和insn.h文件中定义的函数体

首先介绍使用纯软件方式完成二维数组行列和的计算的函数:normal_case


int normal_case(unsigned int array[ROW_LEN][COL_LEN])
{
  volatile unsigned char i=0, j=0;
  volatile unsigned int col_sum[COL_LEN]={0};
  volatile unsigned int row_sum[ROW_LEN]={0};
  volatile unsigned int tmp=0;
  for (i = 0; i < ROW_LEN; i++)
  {
    tmp = 0;
    for (j = 0; j < COL_LEN; j++)
    {
      col_sum[j] += array[i][j];
      tmp += array[i][j];
    }
    row_sum[i] = tmp;
  }

  return 0;
}

这一部分我觉得是没什么可讲的,学过C语言懂得都懂,不懂的……(手动滑稽)

**************************************************************************************************************************

下面是使用NICE协处理器硬件完成的二维数组行列求和的函数: nice_case


int nice_case(unsigned int array[ROW_LEN][COL_LEN])
{
  volatile unsigned char i, j;
  volatile unsigned int col_sum[COL_LEN]={0};
  volatile unsigned int row_sum[ROW_LEN]={0};
  volatile unsigned int init_buf[3]={0};

  custom_lbuf((int)init_buf);
  for (i = 0; i < ROW_LEN; i++)
  {
    row_sum[i] = custom_rowsum((int)array[i]);
  }
  custom_sbuf((int)col_sum);
  

  return 0;
}


这一代码段调用了insn.h中的关于NICE协处理器的三个内联汇编指令函数,介绍如下:


custom_lbuf:

// custom lbuf 
__STATIC_FORCEINLINE void custom_lbuf(int addr)
{
    int zero = 0;
    
    asm volatile (
       ".insn r 0x7b, 2, 1, x0, %1, x0"
           :"=r"(zero)
           :"r"(addr)
     );
}

asm: 是GCC的关键字,表示“在C/C++代码中嵌入内联汇编程序”。

volatile:也是GCC的关键字,表示“不要对这段代码进行任何编译优化”,如果没有添加此关键字,GCC编译器可能将这段代码误优化掉。

“    ”(双引号)  每条汇编指令必须用双引号括起来。

(冒号):第一个冒号后是输出操作数,第二个冒号后是输入操作数,第三个冒号(这里的代码省略没写)后声明在这段汇编代码中可能影响到的寄存器或者存储器。

“=r”、“r”、“m”:这里的r是指register寄存器,m是指memory内存。等号=是对输出操作数的约束,意思是输出的新值会替换旧值。

(   )括号:括号中的名字是原本的C/C++代码中的变量名、表达式,它是连通嵌入式代码和C/C++代码的桥梁。

.insn :这是GNU中的一个编译指示,意思是在当前位置插入一段机器码,格式是  .insn  [指令类别]  opcode,  func3,  func7,  rd,  rs1,  rs2 


详情见GNU官方文档:


例如:  ".insn r  0x7b, 2, 1, x0, %1, x0"    r表示这条指令是R型指令。0x7b是指操作码opcode是1111011,表示这是custom3指令组。func3码(xd-xs1-xs2)是010,表示使用第一源寄存器。func7码是0000001。RD目标寄存器是x0。RS1是%1,即下文输入输出寄存器列表中的第二个寄存器。RS2是x0。

custom_sbuf:


// custom sbuf 
__STATIC_FORCEINLINE void custom_sbuf(int addr)
{
    int zero = 0;
    
    asm volatile (
       ".insn r 0x7b, 2, 2, x0, %1, x0"
           :"=r"(zero)
           :"r"(addr)
     );
}

解读参考上文(狗头.jpg)

custom_rowsum:


// custom rowsum 
__STATIC_FORCEINLINE int custom_rowsum(int addr)
{
    int rowsum;
    
    asm volatile (
       ".insn r 0x7b, 6, 6, %0, %1, x0"
             :"=r"(rowsum)
             :"r"(addr)
     );
    
    return rowsum; 
}

解读参考上文(狗头.jpg)

*******************************************************************************************






由于时间有限、本人能力不足,关于这个源码还有很多东西暂时没写清楚,现在也不太能说明白,可能等学明白以后会再来勘误更新这篇帖子。


我们实际开发协处理器的软件的时候,可以模仿官方的这个demo例程依葫芦画瓢,使用asm volatile内联汇编指令,在C/C++代码中插入机器码,就可以在编写嵌入式软件的时候调用自己设计的协处理器了!是不是很简单呢?(bushi)







喜欢14
用户评论 (3)
  • ZPEI

    2021-07-18 23:31:40 ZPEI 1#

    fan

    将XDXS1XS2的func3码对应XS2的那一位改成1,然后在声明输入的那个冒号后面加上你的C代码中声明的变量

    好的好的,谢谢啦

  • fan

    2021-07-18 22:47:48 fan 2#

    ZPEI

    我想请教一下,如果想使用rs2,需要怎么修改代码呀

    将XDXS1XS2的func3码对应XS2的那一位改成1,然后在声明输入的那个冒号后面加上你的C代码中声明的变量

  • ZPEI

    2021-07-17 16:01:44 ZPEI 3#

    我想请教一下,如果想使用rs2,需要怎么修改代码呀

fan

fan 实名认证

懒的都不写签名

积分
问答
粉丝
关注
  • RV-STAR 开发板
  • RISC-V处理器设计系列课程
  • 培养RISC-V大学土壤 共建RISC-V教育生态
RV-STAR 开发板