在Renode上跑通了一个裸机(baremetal)demo,记录一下过程,为后面的进一步开发做铺垫。
该Demo来自国外一个大神的代码仓库:https://github.com/y2kbugger/baremetal-riscv-renode
有兴趣的同学可以自行下载。
1. 准备工作
1.1 Renode安装
由于我们使用Renode作为仿真平台,因此首先需要完成Renode的安装。以上代码仓库中包含了所有的工程组件,包括Renode源码、RISC-V工具链源码,以及编译所需组件的Makefile,但是实际使用中,可能会出错,所以我选择逐项安装。
Renode的安装在之前的文章里面已经介绍过,在本Demo中可以直接使用,安装方法见之前的博客:初识Renode_牧羊女-CSDN博客
1.2 RISC-V toolchain安装
要想在x86平台上编译RISC-V的binaries,首先需要安装交叉编译工具。针对该Demo的需要,我们只需要安装riscv32-unknown-elf-gcc套件即可,之前的文章我们也介绍了riscv32-unknown-elf-gcc的编译安装过程:编译riscv32-unknown-elf-gcc_牧羊女-CSDN博客
2. 硬件组成和软件代码
该Demo非常简单,堪称嵌入式界的“Hello World”,功能是让一个虚拟LED闪烁。该Demo使用的硬件及软件代码见下面描述。
2.1 硬件组成
Demo使用的硬件组成非常简单,包括一块很小的memory、一个RISC-V CPU、一个GPIO以及两个LED,如下面平台描述文件(vexriscv.repl)所示:
mem: Memory.MappedMemory @ sysbus 0x0
size: 0x00040000
cpu: CPU.VexRiscv @ sysbus
gpio_out: GPIOPort.LiteX_GPIO @ sysbus 0x60000800
type: Type.Out
0 -> led0@0
1 -> led1@0
led0 : Miscellaneous.LED @ gpio_out 0
led1 : Miscellaneous.LED @ gpio_out 1
关于平台描述文件的介绍,见前面的文章: Renode学习:平台描述文件REPL_牧羊女-CSDN博客
2.2 源代码
该Demo的软件代码(baremetal.s)为汇编语言,但也很简单,按照我有限的理解加了一点注释,如下:
#这段有点像C中的宏定义哈
.equ LED, 0x60000800
.equ DELAY_COUNT, 9000000
.equ LED_STATE_INITIAL, 0b00
.equ LED_STATE_TOGGLE_MASK, 0b01
.section .text #定义文本段
.global _start #定义_start为外部程序可访问的标签,类似于我们常用的main()函数
_start:
li a5, LED # 将上面LED表示的值加载到a5寄存器
li a4, LED_STATE_INITIAL # 同上,li为加载立即数指令
li a6, LED_STATE_TOGGLE_MASK
sw a4, 0x0(a5) # store word,将寄存器一个word大小的值存入堆栈,0x0为offset
loop:
li a0, DELAY_COUNT # reset counter
delay_loop:
addi a0, a0, -1 # count down
bnez a0, delay_loop # 条件转移指令,不为0时发生
toggle_led:
lw a4, 0x0(a5) # read in old led state
xor a4, a4, a6 # toggle led state word
sw a4, 0x0(a5) # write new state
jump loop, t0
3. 编译、运行
工程的运行需要三个步骤,分别是:
(1) 从源码baremetal.s中编译出目标二进制文件;
(2) 启动由以上REPL平台描述文件定义的硬件模拟环境;
(3) 将步骤(1)中编译出的elf文件加载到平台模拟器的内存中。
3.1 编译目标文件
目标文件的编译命令行如下:
riscv32-unknown-elf-gcc baremetal.s -ggdb -O0 -o image -ffreestanding -nostdlib
其中,
- riscv32-unknown-elf-gcc为我们在1.2中编译安装的risc-v交叉编译器;
- baremetal.s为软件源码,以上已有介绍;
- -ggdb,使能GDB调试;
- -o image,指定输出elf二进制文件的名称为“image”,可根据自己需要自由修改;
- -ffreestanding,不使用main函数,不假定操作系统的存在;
- -nostdlib,不依赖C标准库。
执行完以上编译命令后,会生成目标ELF文件image:
3.2 仿真脚本
Renode有一个非常方便的地方,就是可以通过一个RESC脚本将所有的步骤串联起来执行,而无需用户在命令行窗口中逐个输入命令,这就大大简化了我们的仿真操作步骤。
工程的仿真脚本(vexriscv.resc)如下:
:name: 1_blinky_VexRiscv
:description: Loader for the baremetal-riscv-renode project example 1 "blinky"
$name?="vexriscv-machine"
using sysbus
mach create $name
machine LoadPlatformDescription @vexriscv.repl
sysbus LoadELF @image
machine StartGdbServer 3333
logLevel -1 sysbus.gpio_out.led0
logLevel -1 sysbus.gpio_out.led1
start
关于脚本中命令的介绍,见之前的文章:Renode学习:Working with machines_牧羊女-CSDN博客
3.3 运行
代码仓库中已经将运行命令也集成到了Makefile文件中,所以我们只需要执行make launch即可使demo运行起来。
Makefile文件如下:
image: baremetal.s
riscv32-unknown-elf-gcc baremetal.s -ggdb -O0 -o image -ffreestanding -nostdlib
launch: image
renode vexriscv.resc
debug:
riscv32-unknown-elf-gdb -x gdbrc
clean:
rm image
运行界面如下: