当前位置: 首页 > news >正文

RISC-V开发环境搭建

RISC-V开发环境搭建

目录

  • 1.1 QEMU模拟器
    • 1.1.1 QEMU简介
    • 1.1.2 QEMU Virt实验平台特性
    • 1.1.3 QEMU优势
  • 1.2 开发环境配置
    • 1.2.1 系统要求
    • 1.2.2 安装QEMU
    • 1.2.3 安装RISC-V编译器
      • 1.2.3.1 官方工具链安装
      • 1.2.3.2 验证编译器安装
      • 1.2.3.3 编译测试程序
    • 1.2.4 验证安装
  • 1.3 调试工具
    • 1.3.1 GDB调试器
      • 1.3.1.1 远程调试
    • 1.3.2 VS Code调试配置
      • 1.3.2.1 安装必要扩展
      • 1.3.2.2 配置launch.json
      • 1.3.2.3 调试步骤
  • VS Code调试界面示例

1.1 模拟器选择

1.1.1 QEMU模拟器

QEMU Virt实验平台模拟的是一款通用的RISC-V开发板,为RISC-V架构学习和开发提供了完整的仿真环境。

1.1.2 NEMU模拟器

NEMU是一个轻量级的RISC-V模拟器,由中科院计算所开发,专门用于教学和学习RISC-V架构。

1.1.3 QEMU Virt实验平台特性

QEMU Virt平台支持以下硬件特性:

  • 最多支持8个RV32GC/RV64GC通用处理器核心
  • 支持CLINT本地中断控制器
  • 支持PLIC中断控制器
  • 支持NOR Flash
  • 支持兼容NS16550的串口
  • 支持RTC
  • 支持8个VirtIO-MMIO传输设备
  • 支持1个PCIe主机桥接设备
  • 支持fw_cfg,用于从QEMU获取固件配置信息

1.1.4 QEMU优势

QEMU基本能满足我们学习RISC-V体系结构的要求,而且免费,调试方便

主要优势:

  1. 免费开源:无需购买昂贵的硬件开发板
  2. 功能完整:支持完整的RISC-V指令集和硬件特性
  3. 调试便利:提供丰富的调试功能和接口
  4. 学习友好:适合初学者理解RISC-V架构
  5. 可扩展性:支持多种RISC-V配置和扩展

1.1.5 NEMU优势

主要优势:

  1. 轻量级:代码简洁,易于理解和学习
  2. 教学友好:专门为教学设计,注释详细
  3. 调试便利:提供丰富的调试功能和接口
  4. 开源免费:完全开源,适合学习研究
  5. 中文支持:有中文文档和社区支持

1.2 开发环境配置

1.2.1 系统要求

  • 操作系统:Ubuntu 24.04 LTS
  • 内存:建议8GB以上
  • 存储:至少10GB可用空间

1.2.2 安装模拟器

1.2.2.1 安装QEMU
sudo apt update
sudo apt install qemu-system-misc
1.2.2.2 安装NEMU

NEMU是一个轻量级的RISC-V模拟器,适合教学和学习使用:

# 克隆NEMU源码
git clone https://github.com/OpenXiangShan/NEMU.git
cd NEMU# 安装依赖
sudo apt install build-essential libreadline-dev# 配置和编译
make menuconfig
make xxxx_defconfig
make -j$(nproc)# 安装到系统路径(可选)
sudo make install

验证NEMU安装:

# 检查NEMU版本
riscv64-nemu-interpreter --version

1.2.3 安装RISC-V编译器

1.2.3.1 官方工具链安装
# 安装RISC-V GNU工具链
sudo apt update
sudo apt install gcc-riscv64-linux-gnu g++-riscv64-linux-gnu# 安装RISC-V GDB调试器
sudo apt install gdb-multiarch# 安装其他开发工具
sudo apt install make cmake git
1.2.3.2 验证编译器安装
# 检查RISC-V GCC版本
riscv64-linux-gnu-gcc --version# 检查RISC-V GDB版本
riscv64-linux-gnu-gdb --version# 检查工具链路径
which riscv64-linux-gnu-gcc
1.2.3.3 编译测试程序

创建C语言环境初始化汇编文件:start.s

.section .text.boot.globl _start
_start:/* Disable M-mode interrupts */csrw mie, zero/* Set up stack, stack size is 4KB */la sp, stacks_startli t0, 4096add sp, sp, t0csrw mscratch, sptail main.section .data
.align  12
.global stacks_start
stacks_start:.skip 4096

创建测试文件 hello.c

#define UART        0x10000000
#define UART_SIZE   4096/* THR:transmitter holding register */
#define UART_DAT    (UART+0x00) /* Data register */
#define UART_IER    (UART+0x01) /* Interrupt enable register */
#define UART_IIR    (UART+0x02) /* Interrupt identification register (read only) */
#define UART_FCR    (UART+0x02) /* FIFO control register (write only) */
#define UART_LCR    (UART+0x03) /* Line control register */
#define UART_MCR    (UART+0x04) /* Modem control register */
#define UART_LSR    (UART+0x05) /* Line status register */
#define UART_MSR    (UART+0x06) /* Modem status register */#define UART_DLL    (UART+0x00)  /* Divisor latch register low 8 bits */
#define UART_DLM    (UART+0x01)  /* Divisor latch register high 8 bits */#define UART_LSR_ERROR  0x80  /* Error */
#define UART_LSR_EMPTY  0x40  /* Transmit FIFO and shift register empty */
#define UART_LSR_TFE    0x20  /* Transmit FIFO empty */
#define UART_LSR_BI	    0x10  /* Break interrupt */
#define UART_LSR_FE	    0x08  /* Framing error (no stop bit received) */
#define UART_LSR_PE	    0x04  /* Parity error */
#define UART_LSR_OE	    0x02  /* Overrun error */
#define UART_LSR_DR	    0x01  /* Data ready in FIFO */#define __arch_getl(a)			(*(volatile unsigned int *)(a))
#define __arch_putl(v,a)		(*(volatile unsigned int *)(a) = (v))
#define __arch_getb(a)			(*(volatile unsigned char *)(a))
#define __arch_putb(v,a)		(*(volatile unsigned char *)(a) = (v))
#define __arch_getq(a)			(*(volatile unsigned long *)(a))
#define __arch_putq(v,a)		(*(volatile unsigned long *)(a) = (v))
#define dmb()		            __asm__ __volatile__ ("" : : : "memory")#define readl(c)	({ unsigned int  __v = __arch_getl((unsigned long)c); dmb(); __v; })
#define writel(v,c)	({ unsigned int  __v = v; dmb(); __arch_putl(__v, (unsigned long)c);})
#define readb(c)	({ unsigned char  __v = __arch_getb(c); dmb(); __v; })
#define writeb(v,c)	({ unsigned char  __v = v; dmb(); __arch_putb(__v,c);})
#define readq(c)	({ unsigned long  __v = __arch_getq(c); dmb(); __v; })
#define writeq(v,c)	({ unsigned long  __v = v; dmb(); __arch_putq(__v,c);})#define UART_DEFAULT_CLOCK 1843200 
#define UART_DEFAULT_BAUD  115200// UART send character function
void uart_send(char c)
{while((readb(UART_LSR) & UART_LSR_EMPTY) == 0);writeb(c, UART_DAT);
}// UART send string function
void uart_send_string(char *str)
{int i;for (i = 0; str[i] != '\0'; i++)uart_send((char) str[i]);
}int main(void)
{unsigned int divisor = UART_DEFAULT_CLOCK / (16 * UART_DEFAULT_BAUD);/* disable interrupt */writeb(0, UART_IER);/* Enable DLAB (set baud rate divisor) */writeb(0x80, UART_LCR);writeb((unsigned char)divisor, UART_DLL);writeb((unsigned char)(divisor >> 8), UART_DLM);/* 8 bits, no parity, one stop bit */writeb(0x3, UART_LCR);/* Enable FIFO, clear FIFO, set 14-byte threshold */writeb(0xc7, UART_FCR);/* Enable receive buffer full interrupt */writeb(0x1, UART_IER);// Output hello worlduart_send_string("hello world\n");// Infinite loop to keep program runningwhile(1) {// Other functionality can be added here}
}

创建链接脚本

ENTRY(_start)SECTIONS
{/* 设置sbi的加载入口地址为0x80000000 */. = 0x80000000,.text.boot : { *(.text.boot) }.text : { *(.text) }.rodata : { *(.rodata) }.data : { *(.data) }. = ALIGN(0x8);bss_begin = .;.bss : { *(.bss*) } bss_end = .;
}

编译测试:

# 编译为RISC-V可执行文件
riscv64-linux-gnu-gcc -save-temps=obj -g -O0 -Wall -nostdlib -mcmodel=medany -mabi=lp64 -march=rv64imafd -fno-PIE -fno-omit-frame-pointer -Wno-builtin-declaration-mismatch -c hello.c -o hello.o
riscv64-linux-gnu-as -g -march=rv64imafd -mabi=lp64 -o start.o start.s
riscv64-linux-gnu-ld -T linker.ld -o hello.elf hello.o start.o# 查看文件信息
file hello.elf# 使用QEMU运行
qemu-system-riscv64 -nographic -machine virt -m 128M  -bios hello.elf 

1.2.4 验证安装

验证QEMU:

qemu-system-riscv64 --version

验证NEMU:

riscv64-nemu-interpreter --version

验证编译器:

riscv64-linux-gnu-gcc --version
riscv64-linux-gnu-gdb --version

1.3 调试工具

1.3.1 GDB调试器

1.3.1.1 远程调试

QEMU支持GDB远程调试:

# 启动QEMU并开启GDB调试端口
qemu-system-riscv64 -machine virt -cpu rv64 -m 128M -nographic -bios hello.elf -s -S# 在另一个终端连接GDB
riscv64-linux-gnu-gdb
(gdb) target remote :1234

1.3.2 VS Code调试配置

VS Code提供了强大的调试功能,可以方便地调试RISC-V程序。通过配置launch.json文件,可以实现图形化的调试体验。

1.3.2.1 安装必要扩展

在VS Code中安装以下扩展:

  1. C/C++ (Microsoft) - 提供C/C++语言支持
  2. C/C++ Extension Pack - 包含调试、智能感知等功能
  3. RISC-V (可选) - RISC-V汇编语言支持

安装方法:

  • 打开VS Code
  • Ctrl+Shift+X 打开扩展面板
  • 搜索并安装上述扩展
1.3.2.2 配置launch.json

在项目根目录创建 .vscode/launch.json 文件:

{"version": "0.2.0","configurations": [{"name": "调试RV64裸机程序(QEMU)","type": "cppdbg","request": "launch","program": "${workspaceFolder}/hello.elf","cwd": "${workspaceFolder}","MIMode": "gdb","miDebuggerPath": "gdb-multiarch","miDebuggerArgs": "--interpreter=mi","stopAtEntry": true,"externalConsole": false,"setupCommands": [{"description": "设置架构为RISC-V 64位","text": "set architecture riscv:rv64","ignoreFailures": true},{"description": "加载符号文件","text": "file ${workspaceFolder}/hello.elf","ignoreFailures": true},{"description": "连接到QEMU GDB服务器","text": "target remote localhost:1234","ignoreFailures": false},{"description": "在_start函数设置断点","text": "break _start","ignoreFailures": true},{"description": "在汇编文件设置断点","text": "break sbi_boot.S:_start","ignoreFailures": true},{"description": "为gdb启用整齐打印","text": "set print pretty on","ignoreFailures": true},{"description": "设置反汇编格式","text": "set disassembly-flavor intel","ignoreFailures": true},{"description": "启用汇编单步调试","text": "set step-mode on","ignoreFailures": true},{"description": "显示汇编代码","text": "set disassemble-next-line on","ignoreFailures": true},{"description": "设置寄存器显示格式","text": "set print registers on","ignoreFailures": true},{"description": "设置源码目录","text": "directory ${workspaceFolder}","ignoreFailures": true},{"description": "启用源码和汇编混合显示","text": "set disassemble-next-line auto","ignoreFailures": true}]}]
}

配置说明:

  • program: 指定要调试的ELF文件路径
  • miDebuggerPath: 使用gdb-multiarch调试器
  • setupCommands: 自动执行的GDB命令
    • 设置RISC-V 64位架构
    • 加载符号文件
    • 连接到QEMU的GDB服务器(端口1234)
    • 在程序入口点设置断点
1.3.2.3 调试步骤

步骤1:启动QEMU调试服务器

在终端中运行以下命令启动QEMU并开启GDB调试端口:

qemu-system-riscv64 -machine virt -cpu rv64 -m 128M -nographic -bios hello.elf -s -S

参数说明:

  • -s: 开启GDB调试服务器(默认端口1234)
  • -S: 启动时暂停,等待GDB连接

步骤2:在VS Code中开始调试

  1. 在VS Code中打开项目文件夹
  2. F5 或点击调试面板的"开始调试"按钮
  3. 选择"调试RV64裸机程序(QEMU)"配置
  4. VS Code将自动连接到QEMU的GDB服务器

步骤3:调试功能使用

  • 设置断点: 在代码行号左侧点击设置断点
  • 单步执行: 使用 F10 (Step Over) 或 F11 (Step Into)
  • 继续执行: 使用 F5 (Continue)
  • 查看变量: 在"变量"面板查看当前作用域的变量
  • 查看寄存器: 在"调试控制台"输入 info registers 查看RISC-V寄存器
  • 查看内存: 在"调试控制台"输入 x/10x $sp 查看栈内存

调试技巧:

  1. 程序入口调试: 程序从 _start 开始执行,这是设置第一个断点的好地方
  2. 汇编调试: 可以查看RISC-V汇编指令的执行过程
  3. 内存布局: 使用 info proc mappings 查看内存映射
  4. 寄存器观察: 重点观察 pc(程序计数器)、sp(栈指针)等关键寄存器

VS Code调试界面示例

下图展示了在VS Code中调试RISC-V程序的界面:
调试截图

界面说明:

  • 左侧面板: 显示变量、监视、调用栈等调试信息
  • 中央代码区: 显示源代码,支持断点设置和单步执行
  • 底部调试控制台: 可以输入GDB命令进行高级调试
  • 调试工具栏: 提供继续、单步、重启等调试控制按钮

文章转载自:

http://7APyk8BP.zpkfb.cn
http://MftScHst.zpkfb.cn
http://Sq5sRBe3.zpkfb.cn
http://bvsa1JU0.zpkfb.cn
http://l55Nb3aK.zpkfb.cn
http://UreIxfDJ.zpkfb.cn
http://mJqIgifh.zpkfb.cn
http://1fJmlNyF.zpkfb.cn
http://PL2MtfYv.zpkfb.cn
http://kj3E184Y.zpkfb.cn
http://8awQ7SIV.zpkfb.cn
http://FWw3veHR.zpkfb.cn
http://1HRoPbiS.zpkfb.cn
http://kapTWK4d.zpkfb.cn
http://TXwRRWkn.zpkfb.cn
http://eHiz8uqq.zpkfb.cn
http://adJKdrdO.zpkfb.cn
http://v79SbRei.zpkfb.cn
http://mBwDejhw.zpkfb.cn
http://1r8fFjAJ.zpkfb.cn
http://zvPq43JM.zpkfb.cn
http://GimS1qoC.zpkfb.cn
http://GBHdjSl7.zpkfb.cn
http://RmREX5GJ.zpkfb.cn
http://DBBQZzSy.zpkfb.cn
http://vlld1EQK.zpkfb.cn
http://qzz21lCc.zpkfb.cn
http://EgfNnmY8.zpkfb.cn
http://gaYv6PQJ.zpkfb.cn
http://ZCRGy4pD.zpkfb.cn
http://www.dtcms.com/a/374609.html

相关文章:

  • Jmeter请求发送加密参数
  • git删除最近一次提交包括历史记录。
  • jmeter 带函数压测脚本
  • jmeter实现两个接口的同时并发
  • 在git仓库的空文件夹中添加.gitkeep文件
  • Vue3+Node.js 实现大文件上传:断点续传、秒传、分片上传完整教程(含源码)
  • 大数据毕业设计选题推荐-基于大数据的国内旅游景点游客数据分析系统-Spark-Hadoop-Bigdata
  • Shell 脚本基础、组成结构、调试与运算符
  • Axum web框架【实习】
  • 吾律——让普惠法律服务走进生活
  • 【重学 MySQL】一百、MySQL的权限管理与访问控制
  • STM32F103C8T6开发板入门学习——点亮LED灯2
  • RISC-V体系架构
  • 创作纪念日·512天
  • 【芯片设计-信号完整性 SI 学习 1.1 -- 眼图、抖动、反射、串扰】
  • 小迪安全v2023学习笔记(八十讲)—— 中间件安全WPS分析WeblogicJenkinsJettyCVE
  • 【Linux】基础指令(下)
  • linux 环境下Docker 安装
  • Nginx 配置
  • 20250910_《SQL Server 数据库事务日志定期清理方案(精简优化版)》以10.1.1.31服务器的gtp-default数据库为例
  • 多输入(input)多输出(output)验证
  • 排查JSch连接SFTP服务器失败的问题
  • JMeter压测过程中监控服务器CPU及内存的方法
  • 整理python快速构建数据可视化前端的Dash库
  • Redis缓存穿透、缓存击穿与雪崩防护及性能优化实战指南
  • ArcGIS学习-20 实战-地形研究
  • Ubuntu下基于Nginx+ffmpeg+video.js的HLS流媒体视频播放方案
  • Vue2 VS Vue3
  • 【ArcGIS】如何编辑图层的属性表
  • VueFlow的箭头怎么调整