- 前言
最近两年RISC-V很火,主要原因还是因为这个处理器是开源的。目前市面上也有有很多的书籍讲RISC-V的原理和架构。我学习RISC-V 主要还是从网络上下载的资料以及视频网站的的代码可以直接用FPGA来做验证。于是我在网上便开始找一些开源代码用来学习,目前从资料的完整性来看,Tiny RISC-V 和 蜂鸟e203我个人觉得是比较好的学习参考资料。这两个RISC-V 处理器我都在XILINX FPGA 上做过一些仿真编译的工作。无奈手上没有合适的板卡实践,一直也就拖了很长时间。这次正好碰上中科亿海微有个开发板测评活动就毫不犹豫的报名了。由于EQ6HL45 的资源还是有限,在评估了该开发板资源之后,我决定在Tiny RISC-V基础上做些RAM的优化调整,并根据最近有个射频模块的小项目结合起来。做一个能够在RISC-V 处理器上完成射频卡的控制和数据采集。
本次实践主要包含3部分:
- Tiny RSIC 的优化和移植
- 射频卡设计和调试
- 射频驱动编译和测试
一下是整个项目的一个框图:
- 中科亿海微EQ6HL45 FPGA 介绍
中科亿海微电子科技有限公司是中国科学院“可编程芯片与系统”研究领域的科研与产业化团队. 这次评测的FPGA便是该公司 eHiChip 家族 FPGA 开发平台产品,开发板采用核心板加扩展板的模式,方便用户对核心板的二 次开发利用,为前期验证和后期应用提供了可能。厂家给的测试配件非常丰富。包装也很不错。装好软件编译一下测试代码,第一天点燃跑马灯过把瘾!
- Tiny RISC-V 介绍
RISC-V是一种指令集架构,和ARM、MIPS这些是属于同一类东西。RISC-V诞生于2010年,最大的特点是开源,任何人都可以设计RISC-V架构的处理器并且不会有任何版权问题。
tinyriscv实现的是一个微RISC-V处理器核,用verilog语言编写,只求以最简单、最通俗易懂的方式实现RISC-V指令的功能,因此没有特意去对代码做任何的优化。
tinyriscv整体框架如图所示:
tinyriscv已经不仅仅是一个内核了,而是一个小型的SOC,包含一些简单的外设,如timer、uart_tx等。
tinyriscv SOC输入输出信号有两部分,一部分是系统时钟clk和复位信号rst,另一部分是JTAG调试信号,TCK、TMS、TDI和TDO。
上图中的小方框表示一个个模块,方框里面的文字表示模块的名字,箭头则表示模块与模块之间的的输入输出关系。
下面简单介绍每个模块的主要作用。
jtag_top:调试模块的顶层模块,主要有三大类型的信号,第一种是读写内存的信号,第二种是读写寄存器的信号,第三种是控制信号,比如复位MCU,暂停MCU等。
pc_reg:PC寄存器模块,用于产生PC寄存器的值,该值会被用作指令存储器的地址信号。
if_id:取指到译码之间的模块,用于将指令存储器输出的指令打一拍后送到译码模块。
id:译码模块,纯组合逻辑电路,根据if_id模块送进来的指令进行译码。当译码出具体的指令(比如add指令)后,产生是否写寄存器信号,读寄存器信号等。由于寄存器采用的是异步读方式,因此只要送出读寄存器信号后,会马上得到对应的寄存器数据,这个数据会和写寄存器信号一起送到id_ex模块。
id_ex:译码到执行之间的模块,用于将是否写寄存器的信号和寄存器数据打一拍后送到执行模块。
ex:执行模块,纯组合逻辑电路,根据具体的指令进行相应的操作,比如add指令就执行加法操作等。此外,如果是lw等访存指令的话,则会进行读内存操作,读内存也是采用异步读方式。最后将是否需要写寄存器、写寄存器地址,写寄存器数据信号送给regs模块,将是否需要写内存、写内存地址、写内存数据信号送给rib总线,由总线来分配访问的模块。
div:除法模块,采用试商法实现,因此至少需要32个时钟才能完成一次除法操作。
ctrl:控制模块,产生暂停流水线、跳转等控制信号。
clint:核心本地中断模块,对输入的中断请求信号进行总裁,产生最终的中断信号。
rom:程序存储器模块,用于存储程序(bin)文件。
ram:数据存储器模块,用于存储程序中的数据。
timer:定时器模块,用于计时和产生定时中断信号。目前支持RTOS时需要用到该定时器。
uart_tx:串口发送模块,主要用于调试打印。
gpio:简单的IO口模块,主要用于点灯调试。
spi:目前只有master角色,用于访问spi从机,比如spi norflash。在后面本次实践当中SPI主要用来控制射频模块
最后在总结一下,tinyriscv处理器核有以下特点:
l 实现了RV32I指令集,通过riscv的RV32I指令兼容性测试,支持以下指令:add addi and andi auipc beq bge bgeu blt bltu bne fence_i jal jalr lb lbu lh lhu lw lui or ori sb sh sw sll slli slt slti sltiu sltu sra srai srl srli sub xor xori;
l 支持RV32M指令集:mul mulh mulhu mulhsu div divu rem remu;
l 采用三级流水线,即取指,译码、访存、执行,回写;
l 可以运行简单的c语言程序。
- 移植Tiny RISC-V 到EQ6HL45 平台
接下来进入到正题环节,本节中我将详细介绍移植tiny risc-v 的过程, 整个过程都是在WIN10系统里完成。
4.1 准备工作
- clone 代码
使用git clone命令下载,不要使用zip方式下载 ,否则有些文件会有格式问题。
git clone https://gitee.com/liangkangnan/tinyriscv.git
- 安装iverilog 工具
可以在这里http://bleyer.org/icarus/下载,安装过程中记得同意把iverilog添加到环境变量中,当然也可以在安装完成后手动进行添加。安装完成后iverilog、vvp和gtkwave等工具也就安装好了。
- 安装GNU工具链
可以通过百度网盘下载(链接: https://pan.baidu.com/s/1bYgslKxHMjtiZtIPsB2caQ 提取码: 9n3c),或者通过微云下载https://share.weiyun.com/5bMOsu9,下载完成后将压缩包解压到本项目的tools目录下。注意目录的层次结构,解压后的工具路径应该如下所示:
tinyriscv oolsgnu-mcu-eclipse-riscv-none-gcc-8.2.0-2.2-20190521-0004-win64in iscv-none-embed-gcc
- 安装make 工具
可以通过百度网盘下载(链接: https://pan.baidu.com/s/1nFaUIwv171PDXuF7TziDFg 提取码: 9ntc),或者通过微云下载https://share.weiyun.com/59xtmWR,下载完成后直接解压,然后将make所在的路径添加到环境变量里。
- 安装python3
到python官网下载win版本的python,注意要下载python3版本的。我之前电脑上有ANACOND也是可以的。
- 安装Visual studio code
一个很好用代码编辑工具,强烈推荐。下载地址:
Visual Studio Code - Code Editing. Redefined
- 懒癌打包
如果你也是WIN10系统,也可以直接从我的百度网盘里直接下载以上所有文件:
4.2 代码整理
在作者的readme 里面已经有了详细的仿真测试指导,本文就不重复描述了。这里主要介绍一下如何将代码移植到中科艺海微FPGA,也就是编译源码里面的RTL 文件。下面的图片是源码里的RTL文件目录:
我在FPGA目录里面创建一个新的文件命名为EQ6HL45,并把源码中的RTL放进该文件夹如图:
这里需要注意几个问题,这是我在后面遇到的,可以先提前改一下,一个是头文件可以检查一下是不是对应的位置:
另一个是把ROM/RAM的深度改小一点,因为该系类FPGA的片内RAM 不够。
4.3 Elinx 工程创建和编译
先认真阅读代码,理清文件的层次结构。清楚了整个逻辑框架,接下来就可以打开ELINX软件开始创建工程了
具体的创建过程,本文也不赘述了,在elinx 软件使用手册里写的非常清楚。这里没有特别的技巧,如果有问题的根据提示一般也都可以解决,如果一切顺利的话在综合之后你便可以看到整个工程的层次结构如下:
接下来便可以在layout 栏目里面选择io planning 做管脚约束:
接下来布局布线,生成bit文件就可以下载到FPGA 里面啦。
4.4
- FPGA image 下载与测试
关于如果下载到FPGA RAM 还是下载到外部flash里面,在中科艺海微的用户手册里面也有详细的描述。本文不描述。建议可以直接下载到FLASH里面,断电不丢失,方便测试。另外一个比较好的建议增加一些LED调试功能,可以方便调试逻辑。
- 编写第一个C语言程序hello world
6.1先跑通测试代码
C语言程序例程位于源码目录下testsexample目录里。
下面以simple程序为例进行说明。
打开CMD窗口,进入到testsexamplesimple目录,执行以下命令编译:
make
编译过程界面
编译结束之后会有bin文件,这里注意的地方是MAKE 要设置好环境变量。
编译成功之后,进入到sim目录,执行以下命令开始测试:
python .sim_new_nowave.py .. estsexamplesimplesimple.bin inst.data
可以看到PASS界面
- 使用串口下载编译文件
通过UART方式下载前需要先使能UART debug模块。在约束文件里指定的uart_debug_en引脚,当其输入为高电平时表示使能UART debug模块,输入为低电平时表示关闭UART debug模块。
当使能了UART debug模块后,就可以通过tools/tinyriscv_fw_downloader.py脚本来下载程序。
tinyriscv_fw_downloader.py脚本使用方法:
python tinyriscv_fw_downloader.py 串口号 bin文件
打开CMD窗口,进入到tools目录,比如输入以下命令:
即可下载firmwarm.bin程序到软核里。下载完后,先关闭UART debug模块,然后按板子上的复位(rst)按键即可让程序跑起来。
- 增加一个SPI接口射频模块
- 使用C语言编写射频模块驱动
- 进阶部分-移植FreeTOS