1 运行 FreeRTOS 的最低硬件要求
一个 RISC-V core 加片上存储器,以及片上外设 uart,已经具备了计算机的5大组成部分——运算器、控制器、存储器、输入设备、输出设备,可以构成一个最简单的单片机。
给上面这个单片机再添加片上 timer 就具备了运行 FreeRTOS 的最低硬件条件。也就是说,有了下面的硬件,就具备了运行 FreeRTOS 的硬件条件:
- RISC-V core (要能够处理 timer 中断)
- 存储器
- uart
- timer
RISC-V core 至少要包含下面的模块:
- 控制单元(Control Unit, CU)
- 算术逻辑单元(Arithmetic Logic Unit, ALU)
- 寄存器(Registers): pc, gpr, csr
- CLINT (Core-Local Interruptor): 参考 SiFive FE310-G002 芯片。
- 总线接口单元(Bus Interface Unit, BIU)
2 至少应该实现的 RISC-V 指令集
- 要运行 FreeRTOS 至少要支持 RV32I 和 Zicsr 指令集
- RV32I was designed to be sufficient to form a compiler target and to support modern operating system environments.
- 中断需要 CSR ,所以,需要支持 Zicsr 指令集
3 模拟器中的模块
3.1 执行一条指令的步骤
这里是开发功能精确 ISS,参照早期 ARM CPU 的三级流水——取指、译码、执行,就够用了。
RRV-ISS 中执行一条指令,可以分为三步:取指、译码、执行。
3.2 RRV-ISS 中大的功能模块
- core
- 寄存器:pc,gpr,csr
- 取指:去 pc 指定的地址取指令,并把 pc 更新到下一条指令的起始地址
- 译码:解析指令,根据指令获取操作数以及运算的函数;执行阶段就是一行调用运算函数的代码
- 外设
- 存储器
- CLINT:其中包含了 timer
- uart
- bus:所有外设(片上外设、片外外设)都通过 bus 模块的接口进行访问
- loader:将程序加载到 memory
3.3 rust 工程的 crate & mod 结构
- 该工程使用 workspace 进行组织
- 将通过执行一条 add 指令来打通各个 mod 之间的接口
- 随着项目的深入,模块/接口可能会变化
├── Cargo.toml
├── cpu_peripherals
│ ├── Cargo.toml
│ └── src
│ ├── clint.rs
│ ├── lib.rs
│ ├── mem.rs
│ └── uart.rs
├── iss # 指令集模拟器的 binary crate
│ ├── Cargo.toml
│ └── src
│ └── main.rs
├── rv_core
│ ├── Cargo.toml
│ └── src
│ ├── core.rs
│ ├── csr.rs
│ ├── decoder.rs
│ ├── fetch.rs
│ └── lib.rs
├── sim_lib # 模拟器的 mod 库
│ ├── Cargo.toml
│ └── src
│ ├── bus.rs
│ ├── lib.rs
│ ├── loader.rs
│ └── simulator.rs
└── tests # 整个工程的集成测试
├── Cargo.toml
├── src
│ └── lib.rs
└── tests
└── exec_add_instr.rs # 执行一条 add 指令
4 让大模型生成工程的打桩代码
4.1 生成打桩代码提示词
任务:请根据“cargo workspace 目录结构”给工程打桩
角色:资深的指令集模拟器开发者,你同时具有丰富的软件架构设计经验、rust程序开发经验以及RISC-V ISA设计经验
背景:正在使用rust编写RISC-V的ISS
要求
==============
1. 一步一步思考,给出完整代码
2. 在 cpu_peripherals/src/lib.rs 中定义一个Device trait,Device提供按字节、半字、字、任意长度进行读写的接口,所有的读写都有可能失败
3. 所有peripherals都需要实现Device trait
4. 在 cpu_peripherals/src/lib.rs 中定义Device type的enum,每个peripheral有对应的type,Device trait有获取type的接口
5. bus 要管理各种实现了 Device 接口的设备,每个设备有对应的地址范围,需要提供根据地址查找对应设备的接口,要尽可能提高查找设备的速度
6. 代码中要有必要的错误处理
7. 添加单元测试
8. 添加集成测试,集成测试放在tests/tests/exec_add_instr.rs
9. 注释使用英文
10. 实现所有的rs文件
cargo workspace 目录结构:
```bash
├── Cargo.toml
├── cpu_peripherals
│ ├── Cargo.toml
│ └── src
│ ├── clint.rs
│ ├── lib.rs
│ ├── mem.rs
│ └── uart.rs
├── iss # 指令集模拟器的 binary crate
│ ├── Cargo.toml
│ └── src
│ └── main.rs # 作为入口文件,调用各个module的接口
├── rv_core
│ ├── Cargo.toml
│ └── src
│ ├── core.rs # core 的主体
│ ├── csr.rs # 模拟csr
│ ├── decoder.rs
│ ├── fetch.rs
│ └── lib.rs
├── sim_lib # 模拟器的 mod 库
│ ├── Cargo.toml
│ └── src
│ ├── bus.rs # 模拟总线,管理各种设备
│ ├── lib.rs
│ ├── loader.rs # 加载 ELF 文件到模拟器内存
│ └── simulator.rs # 模拟器的主体
└── tests # 整个工程的集成测试
├── Cargo.toml
├── src
│ └── lib.rs
└── tests
└── exec_add_instr.rs # 执行一条 add 指令的集成测试
```
4.2 调整生成的代码
4.2.1 修改代码,保证下面的命令结果都正常
cargo check
cargo test
cargo run
4.2.2 增加 log 机制
使用 tracing 库,来做 ISS 的 log。
tracing 库的介绍详见:Rust 语言的全链路追踪库 tracing
4.2.3 统一的错误处理
- 基于 thiserror 库,定义每个 library crate 的 error 类型。
- 参考资料:18|错误处理:为什么Rust的错误处理与众不同?
- 使用 thiserror 定义 trap。
4.3 解码
4.4 测试
riscv-software-src: Welcome to the RISC-V Software Repos
riscv: Welcome to the RISC-V Specifications