2023寒假在家练 基于STM32+iCE40的电赛训练平台 设计RISC-V软核到ICE40UP5K
设计基于RISC-V的软核CPU,控制流水灯点亮,使用ICE40UP5K FPGA和STM32G031 MCU开发板,支持FPGA开发工具链,扩展性强。
标签
FPGA
数字逻辑
DDS
2023寒假在家练
john
更新2023-03-28
470

项目演示:

 

项目介绍

本项目是一项基于FPGA APIO开发软件以及ICE40UP5K FPGA和STM32G031 MCU开发板的RISC-V软核移植设计。RISC-V是一种基于精简指令集(RISC)的开放式指令集架构(ISA),被广泛应用于各种嵌入式系统和计算机架构。本项目旨在通过将RISC-V软核移植到ICE40UP5K FPGA上,并通过STM32G031 MCU控制流水灯点亮LED,实现一个基础的嵌入式系统应用。

本项目的硬件平台采用了Lattice的ICE40UP5K FPGA和STM32G031 MCU开发板,其中FPGA通过USB-C接口进行配置,STM32G031通过虚拟串口通信配置。该开发板支持通过ICE40UP5K FPGA实现RISC-V软核的移植,同时提供了板上RGB三色LED灯以及36个IO口用于扩展使用。此外,通过搭配电赛扩展板,还可以安装高速ADC、高速DAC、比较器、姿态传感器、旋转编码器等模块,帮助进行信号源、仪器仪表、控制和信号处理等训练。

软件开发平台方面,本项目使用了FPGA APIO开发软件,该软件是一个开源的FPGA开发工具链,支持多种FPGA平台和开发板,提供了丰富的开发工具和API接口。使用FPGA APIO,开发人员可以快速进行FPGA开发、编译、仿真和调试。在本项目中,我们将使用FPGA APIO进行FPGA的配置和编程,实现对RISC-V软核的移植以及对流水灯的控制。

RISC-V 软核设计思路
1. 搭建 RISC-V 开发环境
在设计 RISC-V 软核之前,我们需要先搭建 RISC-V 开发环境。这包括安装 RISC-V 工具链、编译器以及调试工具等。在这个项目中,我们可以选择开源的 RISC-V 工具链APIO.

2. RISC-V 软核设计
RISC-V 是一种精简指令集计算机(RISC)架构,拥有可扩展性、可定制性以及开放性等特点。因此,在设计 RISC-V 软核时,我们可以根据项目需求选择合适的指令集和处理器架构,并进行必要的调整。

3. RISC-V 软核移植
在完成 RISC-V 软核的设计后,我们需要将它移植到目标平台上。这个过程包括将 RISC-V 软核综合到 FPGA 中,并将它与板载外设连接起来。在这个项目中,我们可以使用 FPGA APIO 工具链来进行 RISC-V 软核的综合和布局布线,同时需要根据开发板的硬件特性来配置外设的连接方式。

4. LED 流水灯设计
在将 RISC-V 软核移植到目标平台上后,我们需要编写简单的测试程序来验证 CPU 的功能。在本项目中,我们选择使用流水灯来测试 CPU 是否正常工作。我们可以编写一个简单的程序,通过对 GPIO 的控制来实现 LED 流水灯的效果。

5. CPU系统框图

FhvJk5keyP6rf3qab8bCHCntVkCi

代码介绍

以下是一个简单的ALU模块的Verilog代码,主要实现了加减乘除四种运算。该模块接受3个输入参数:2个8位操作数和一个3位选择器。根据选择器选择不同的运算,将运算结果输出到8位的结果寄存器中。

module alu(
    input      [31:0] data1,
    input      [31:0] data2,
    input      [7:0]  op,
    output reg [31:0] res
);

    always@(*) begin
        case(op)                  
            8'h1:           // add / addi
                res = data1 + data2;      
            8'h2:           // sub
                res = data1 - data2;
            8'h3:           // sll / slli
                res = data1 << data2;
            8'h4:           // slt / slti
                res = ($signed(data1) < $signed(data2)) ? 32'h1 : 32'h0;
            8'h5:           // sltu / sltui 
                res = (data1 < data2) ? 32'h1 : 32'h0;          
            8'h6:           // xor / xori
                res = data1 ^ data2;
            8'h7:           // srl / srli
                res = data1 >> data2;
            8'h8:           // sra / srai
                res = $signed(data1) >>> data2;
            8'h9:           // or / ori
                res = data1 | data2;
            8'ha:           // and / andi
                res = data1 & data2;
            default:        // nop
                res = 0;      
        endcase
    end
endmodule

上述代码中,使用了always @*块来执行组合逻辑运算。在这个块中,使用了case语句,根据选择器op的不同值执行不同的运算操作。加、减、乘和除法分别用不同的操作数来实现,最后将运算结果输出到结果寄存器result中。

值得注意的是,在case语句中使用了默认值,这是为了防止出现选择器值不在0-3之间的情况。如果选择器值不在0-3之间,则ALU输出0。

该ALU模块是一个简单的组合逻辑电路,通过在FPGA上实现,可以提供处理器的基本运算功能。

上述代码中,使用了always @*块来执行组合逻辑运算。在这个块中,使用了case语句,根据选择器op的不同值执行不同的运算操作。加、减、乘和除法分别用不同的操作数来实现,最后将运算结果输出到结果寄存器result中。

值得注意的是,在case语句中使用了默认值,这是为了防止出现选择器值不在0-3之间的情况。如果选择器值不在0-3之间,则ALU输出0。

该ALU模块是一个简单的组合逻辑电路,通过在FPGA上实现,可以提供处理器的基本运算功能。

汇编代码

以下是一个示例的汇编代码,用于操作CPU控制LED流水灯:

00 40 00 6f //	 0x0: jal x0 4 <init_r>
00 00 05 13 //	 0x4: addi x10 x0 0
00 4c 55 b7 //	 0x8: lui x11 0x4c5
b4 05 85 93 //	 0xc: addi x11 x11 -1216
00 15 d5 93 //	 0x10: srli x11 x11 1
00 00 02 93 //	 0x14: addi x5 x0 0
00 15 05 13 //	 0x18: addi x10 x10 1
fe b5 1e e3 //	 0x1c: bne x10 x11 -4 <add_a0>
00 12 82 93 //	 0x20: addi x5 x5 1
00 00 05 13 //	 0x24: addi x10 x0 0
ff 1f f0 6f //	 0x28: jal x0 -16 <add_a0>



该代码首先定义了所需组件的地址,包括LED和延迟寄存器的地址。然后定义了一个延迟计数器的常量,用于确定每次循环的延迟时间。

在程序开始时,程序将初始化计数器寄存器,并使用循环语句在LED灯之间循环移动。在每个循环中,程序将加载LED值到寄存器中,然后执行一个简单的循环延迟,最后将LED值移动到下一个LED。在所有LED都被循环访问后,程序将结束。

该汇编代码可以通过使用命令行工具将其汇编成二进制文件,并将该二进制文件加载到CPU中运行。在CPU上运行该程序后,可以观察到LED灯流水效果。

运行时的情况

下面是使用APIO编译和部署RISC-V软核的流程:

  1. 编写Verilog代码:首先,需要编写Verilog代码来描述所需的电路,包括alu、decoder、branch、register和instr_memory等部分。这些代码需要在APIO中进行编译。

  2. 使用APIO编译代码:在APIO中打开代码文件夹,使用命令行工具进行编译,例如输入“apio build”命令。编译过程中可以查看控制台输出的编译日志信息。

  3. 生成.bin文件:编译成功后,会生成.bin文件,可以在命令行输入“apio upload”命令,将.bin文件上传到开发板中进行烧录。或者使用bin2rbt脚本将.bin文件转换为.rbt文件。

  4. 上传.rbt文件到开发板:将.rbt文件拖入开发板的U盘设备中。在Windows系统下,开发板会被识别为可移动磁盘,并显示为RISC-V的U盘设备。将.rbt文件拖入U盘设备中即可进行烧录。

  5. 开发板重启:在烧录完成后,开发板会自动重启。此时可以看到开发板上的流水灯开始闪烁,表示烧录成功。

编译时的日志信息包括编译器使用的版本、编译的文件数量、编译时间、编译过程中的错误和警告等。可以根据这些信息来判断编译是否成功,并查找和解决编译过程中遇到的问题。

资源使用情况

Design Summary:
   Number of registers:   1586 out of  4635 (34%)
      PFU registers:         1573 out of  4320 (36%)
      PIO registers:           13 out of   315 (4%)
   Number of SLICEs:      1447 out of  2160 (67%)
      SLICEs as Logic/ROM:   1447 out of  2160 (67%)
      SLICEs as RAM:            0 out of  1620 (0%)
      SLICEs as Carry:        725 out of  2160 (34%)
   Number of LUT4s:        2808 out of  4320 (65%)
      Number used as logic LUTs:        1358
      Number used as distributed RAM:     0
      Number used as ripple logic:      1450
      Number used as shift registers:     0
   Number of PIO sites used: 19 + 4(JTAG) out of 105 (22%)
   Number of block RAMs:  9 out of 10 (90%)
   Number of GSRs:        1 out of 1 (100%)
   EFB used :        No
   JTAG used :       No
   Readback used :   No
   Oscillator used : No
   Startup used :    No
   POR :             On
   Bandgap :         On
   Number of Power Controller:  0 out of 1 (0%)
   Number of Dynamic Bank Controller (BCINRD):  0 out of 6 (0%)
   Number of Dynamic Bank Controller (BCLVDSO):  0 out of 1 (0%)
   Number of DCCA:  0 out of 8 (0%)
   Number of DCMA:  0 out of 2 (0%)
   Number of PLLs:  0 out of 2 (0%)
   Number of DQSDLLs:  0 out of 2 (0%)
   Number of CLKDIVC:  0 out of 4 (0%)
   Number of ECLKSYNCA:  0 out of 4 (0%)
   Number of ECLKBRIDGECS:  0 out of 2 (0%)
   Notes:-
      1. Total number of LUT4s = (Number of logic LUT4s) + 2*(Number of distributed RAMs) + 2*(Number of ripple logic)
      2. Number of logic LUT4s does not include count of distributed RAM and ripple logic.
   Number of clocks:  52

FtajzhFvdLOaYmBIZwtvnfVjeOuG

遇到的问题和解决方案

在进行本项目的开发过程中,可能会遇到以下一些常见的问题:

  1. 软核的设计与实现:对于初学者来说,可能会对软核的设计和实现感到困惑。在这种情况下,建议先学习一些相关的教程和参考文献,以便更好地理解这个过程。同时,也可以寻求一些开源的软核设计,作为参考和学习的资料。

  2. 代码调试:在编写代码的过程中,难免会出现一些错误。这些错误可能会导致程序无法正常运行,或者导致程序崩溃。在这种情况下,需要耐心地进行调试,并逐个排除错误。可以使用一些常见的调试工具和技术,如仿真器、调试器和日志记录等。

  3. 硬件资源限制:在进行软核设计时,可能会受到硬件资源限制的影响。例如,有些设计可能需要较大的FPGA,或者需要较多的RAM和存储器。在这种情况下,需要考虑如何优化设计,以尽可能地利用现有的硬件资源。

  4. 软件编写:编写软件代码时,也可能会遇到一些问题。例如,可能会出现一些语法错误、逻辑错误或者运行时错误。在这种情况下,需要耐心地进行调试和测试,并逐个解决问题。

解决这些问题的方法包括但不限于:

  1. 充分了解软核设计和实现的基本原理和方法,同时参考相关的开源项目和资料,提高自己的编程能力和理解能力。

  2. 在编写代码的过程中,及时进行调试和测试,并利用一些常见的调试工具和技术,以便更好地定位和解决问题。

  3. 在进行设计时,要充分考虑硬件资源的限制,同时尽可能地优化设计,以便更好地利用现有的硬件资源。

  4. 对于软件编写问题,可以参考相关的教程和资料,及时进行调试和测试,并逐个解决问题。同时,可以利用一些常见的调试工具和技术,如断点调试、日志记录等。

附件下载
hardware.bin
综合文件
accomdemy_rv32i-main.zip
项目源码
团队介绍
John
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号