NICE协处理器

赛题要求:

  对蜂鸟E203 RISC-V内核进行运算算子(譬如加解密算法、浮点运算、矢量运算等)的扩展,可通过NICE协处理器接口进行添加,也可直接实现RISC-V指令子集(譬如P扩展、F/D扩展、V扩展、B扩展、K扩展等)

  对于采用NICE协处理器接口进行的扩展实现,需要在蜂鸟软件开发平台HBird SDK中进行相关软件驱动的添加

  • 实现思路:

    • 1.硬件设计,编写相应的verilog文件,需要注意的是NICE协处理器定义了一些基本的接口;
    • 2.编写驱动,通过内联汇编的伪指令.insn配置相关的驱动设置;
    • 3.编写用于测试的.C文件
  • 参考示例:

    • 背景: 假设有一个3行3列的矩阵按顺序存储在存储器中,每个元素都是32位的整数,目标进行逐行和逐列的累加和,若采用C语言调用主数据通路进行实现,基本思路是循环,按行/列读取各个元素然后相加得到各行/列的累加和,将其转换为汇编语言,则需要约上百个周期才能完成全部运算。

    • 硬件实现:(不太好写)

      (e203_hbirdv2-master\e203_hbirdv2-master\rtl\e203\subsys\e203_subsys_nice_core.v)

      ->NICE协处理器工作机理:

      • 请求通道:主处理器在流水线的EXU级时,将指令的编码信息和源操作数传输到协处理器。
      • 反馈通道:协处理器告诉主处理器其已完成了该指令,并将结果反馈到主处理器。
      • 存储器请求通道:协处理器向主处理器发起存储器读写请求。
      • 存储器反馈通道:主处理器向协处理器写回存储器读写结果。

      ->NICE示例协处理器的设计:

      控制模块(和主处理器通过NICE协处理器的接口进行交互)+累加器(累加运算)

      ->NICE示例协处理器的自定义指令

      ->verilog文件中包含内容:

      自定义指令的编码+各模块功能实现(以状态机实现的转换)

    • 软件驱动:

      (nuclei-board-labs-master\nuclei-board-labs-master\e203_hbirdv2\common\demo_nice\insn.h)

      基本格式:

      .insn r opcode, func3, func7, rd, rs1, rs2
    //.insn告知编译器当前的指令是.insn形式的指令
    //r用来表示指令类型为R-type
    //opcode、func3、func7、rd、rs1、rs2分别代表R类型指令格式的各位域

      具体实现:(累加和)

      // 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)
    );
    } // 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)
    );
    } // 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;
    }
    • 测试程序:(nuclei-board-labs-master\nuclei-board-labs-master\e203_hbirdv2\common\demo_nice\insn.c --> 功能实现;nuclei-board-labs-master\nuclei-board-labs-master\e203_hbirdv2\common\demo_nice\main.c --> 顶层文件,测试输出)
      /***********************************insn.c*********************************/
    // 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;
    }
    } // nice_case:调用NICE协处理器实现的累加操作
    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);
    } /***********************************main.c*********************************/
    // 主要就是调用两个函数然后输出结果
    int main(void)
    {
    int i=100;
    int arr[4]={1,2,3,4};
    unsigned int array[ROW_LEN][COL_LEN]=
    {{10,20,30},
    {20,30,40},
    {30,40,50}
    };
    unsigned int begin_instret, end_instret, instret_normal, instret_nice;
    unsigned int begin_cycle, end_cycle, cycle_normal, cycle_nice; printf("**********************************************\n");
    printf("** begin to sum the array using ordinary add sum\n");
    begin_instret = __get_rv_instret();
    begin_cycle = __get_rv_cycle(); normal_case(array); end_instret = __get_rv_instret();
    end_cycle = __get_rv_cycle(); instret_normal = end_instret - begin_instret;
    cycle_normal = end_cycle - begin_cycle;
    printf("\n\n"); printf("**********************************************\n");
    printf("** begin to sum the array using nice add sum\n");
    begin_instret = __get_rv_instret();
    begin_cycle = __get_rv_cycle(); nice_case(array); end_instret = __get_rv_instret();
    end_cycle = __get_rv_cycle(); instret_nice = end_instret - begin_instret;
    cycle_nice = end_cycle - begin_cycle; printf("**********************************************\n");
    printf("** performance list \n"); printf("\t normal: \n");
    printf("\t instret: %d, cycle: %d \n", instret_normal, cycle_normal);
    printf("\t nice : \n");
    printf("\t instret: %d, cycle: %d \n", instret_nice , cycle_nice ); printf("**********************************************\n\n"); printf("* * * * ***** * ******* *** \n");
    printf("** * * * * * * * * \n");
    printf("* * * * * * * * * \n");
    printf("* * * * * * * ***** * \n");
    printf("* * * * * * * * * \n");
    printf("* ** * * * * * * * \n");
    printf("* * ***** ***** ******* ******* *** \n"); printf("\n\n**********************************************");
    return 0;
    }
    • 实际测试:

      • 法一:(不推荐)通过.c文件配置工程,参考这里(5.3. 无模板手动创建项目)

      • 法二:(推荐)

        • 创建HelloWorld例程,删除左侧相应工程目录下application/main.c文件

        • 将我们所编写的软件驱动文件和测试文件放入该目录下

        • 点击锤子进行编译,做好硬件连接后,点击️️绿色的三角运行。

      采用NICE协处理器进行的累加所用的指令数和周期数都远小于普通情况,如下图所示。

  • 一些疑惑:

    • 对于NICE协处理器和普通的情况,均进行了诸如循环读寄存器数据之类的操作,那么实现NICE协处理器相较于普通情况的优化体现在什么方面,节约的是进行取数+计算的时间,还是其他诸如循环控制等的时间;
    • 是否应该根据后续的系统及应用来判断进行什么样的扩展;
    • 对于添加了NICE协处理器的内核,其跑分结果应该有所提高,那么该如何通过跑分的程序测试出来;

3.NucleiStudio+Vivado联合仿真教程

  猜测后续的工作流程:

  • Benchmark:

    Vivado中修改RTL设计-->NucleiStudio中跑分验证/Vivado中仿真验证(尝试跑通中);

  • 指令集扩展:

    Vivado中添加RTL设计+IDE中添加软件驱动-->NucleiStudio中验证功能/Vivado中仿真验证功能(当前尝试的NICE协处理器可仿真验证)

  编写了一个Nucleistudio+Vivado联合仿真的教程,或许会有用((。

手把手教你蜂鸟e203协处理器的扩展的更多相关文章

  1. 手把手教你蜂鸟e203移植(以Nexys4DDR为例)

    准备工作:(网盘链接:) 1.蜂鸟e203的RTL源码: 2.一段分频代码: 3.顶层设计文件(system.v) 4.开发板文件: 5.Nexys4DDR电路图: 6.Nexys4DDR管脚约束模板 ...

  2. 手把手教你开发chrome扩展一:开发Chrome Extenstion其实很简单

    手把手教你开发chrome扩展一:开发Chrome Extenstion其实很简单   手把手教你开发chrome扩展一:开发Chrome Extenstion其实很简单 手把手教你开发Chrome扩 ...

  3. 菜鸟-手把手教你把Acegi应用到实际项目中(8)-扩展UserDetailsService接口

    一个能为DaoAuthenticationProvider提供存取认证库的的类,它必须要实现UserDetailsService接口: public UserDetails loadUserByUse ...

  4. 手把手教你开发chrome扩展

    转载:http://www.cnblogs.com/walkingp/archive/2011/04/04/2003875.html 手把手教你开发chrome扩展一:开发Chrome Extenst ...

  5. 手把手教你Chrome扩展开发:本地存储篇

    手把手教你开发chrome扩展一:开发Chrome Extenstion其实很简单 手把手教你开发Chrome扩展二:为html添加行为 手把手教你开发Chrome扩展三:关于本地存储数据 HTML5 ...

  6. 手把手教你开发Chrome扩展三:关于本地存储数据

    手把手教你开发chrome扩展一:开发Chrome Extenstion其实很简单 手把手教你开发Chrome扩展二:为html添加行为 手把手教你开发Chrome扩展三:关于本地存储数据 HTML5 ...

  7. 手把手教你开发Chrome扩展二:为html添加行为

    手把手教你开发chrome扩展一:开发Chrome Extenstion其实很简单 手把手教你开发Chrome扩展二:为html添加行为 手把手教你开发Chrome扩展三:关于本地存储数据 上一节我们 ...

  8. 手把手教从零开始在GitHub上使用Hexo搭建博客教程(二)-Hexo参数设置

    前言 前文手把手教从零开始在GitHub上使用Hexo搭建博客教程(一)-附GitHub注册及配置介绍了github注册.git相关设置以及hexo基本操作. 本文主要介绍一下hexo的常用参数设置. ...

  9. 手把手教你写Sublime中的Snippet

    手把手教你写Sublime中的Snippet Sublime Text号称最性感的编辑器, 并且越来越多人使用, 美观, 高效 关于如何使用Sublime text可以参考我的另一篇文章, 相信你会喜 ...

  10. 30分钟手把手教你学webpack实战

    30分钟手把手教你学webpack实战 阅读目录 一:什么是webpack? 他有什么优点? 二:如何安装和配置 三:理解webpack加载器 四:理解less-loader加载器的使用 五:理解ba ...

随机推荐

  1. vue基础系列文章12---创建脚手架

    一.交互式命令行创建 1.运行 vue create myvue 选择默认创建模式,会在指定的文件夹下创建文件 2.进入到myvue文件夹,运行:npm  run serve 3.访问本地的地址就可以 ...

  2. 【Java】先return还是先finally

    之前调试只发现有的方法执行完return语句后再执行finally,但是没有细究 最近debug代码的时候发现,不同返回类型的方法,return和finally执行顺序竟然不一样 先看返回类型为voi ...

  3. 虚拟桌宠模拟器:VPet-Simulator,一个开源的桌宠软件, 可以内置到任何WPF应用程序

    虚拟桌宠模拟器:VPet-Simulator,一个开源的桌宠软件, 可以内置到任何WPF应用程序 虚拟桌宠模拟器 一个开源的桌宠软件, 可以内置到任何WPF应用程序 获取虚拟桌宠模拟器 OnSteam ...

  4. 2.6 Windows驱动开发:使用IO与DPC定时器

    本章将继续探索驱动开发中的基础部分,定时器在内核中同样很常用,在内核中定时器可以使用两种,即IO定时器,以及DPC定时器,一般来说IO定时器是DDK中提供的一种,该定时器可以为间隔为N秒做定时,但如果 ...

  5. C/C++ 类与构造析构等知识

    简单定义类 #include <iostream> #include <string> using namespace std; class Student { public: ...

  6. ***.jar没有主清单属性

    工具环境 idea centos7.9 现象 java -jar运行jar包提示没有主清单属性,如下图所示: 这个jar包,是通过idea打包的,打包方法:idea---File---Project ...

  7. 【双指针】双指针算法详解两道经典OJ【力扣27,力扣26,力扣38】超详细算法教程

    [双指针]双指针算法详解两道经典OJ[力扣27,力扣26,力扣38]超详细算法教程 今天又又到了我们刷力扣题的时间啦! 今天博主给大家带来的三道题是: 27. 移除元素 26. 删除有序数组中的重复项 ...

  8. 使用OpenCV实现视频去抖

    使用OpenCV实现视频去抖 整体步骤: 设置输入输出视频 寻找帧之间的移动:使用opencv的特征检测器,检测前一帧的特征,并使用Lucas-Kanade光流算法在下一帧跟踪这些特征,根据两组点,将 ...

  9. 由反射引出的Java动态代理与静态代理

    写在开头 在<深入剖析Java中的反射,由浅入深,层层剥离!>这篇文章中我们讲反射时,曾提到过Java的动态代理中使用了反射技术,那么好,今天我们要就着反射的索引,来学习一下Java中的代 ...

  10. 京豆薅羊毛新姿势-docker方式

    背景 上周看脉脉的时候看到下面这个帖子,领导让搞项目容器化,但是楼主没搞过,对新东西有畏惧感,怂了,然后把机会白白送给其他同事了. 想来我也是差不多这样的,刚到阿里工作的时候,有个好的项目机会来了,领 ...