2. 设计模拟器架构

1 运行 FreeRTOS 的最低硬件要求

一个 RISC-V core 加片上存储器,以及片上外设 uart,已经具备了计算机的5大组成部分——运算器、控制器、存储器、输入设备、输出设备,可以构成一个最简单的单片机。

给上面这个单片机再添加片上 timer 就具备了运行 FreeRTOS 的最低硬件条件。也就是说,有了下面的硬件,就具备了运行 FreeRTOS 的硬件条件:

  1. RISC-V core (要能够处理 timer 中断)
  2. 存储器
  3. uart
  4. timer

RISC-V core 至少要包含下面的模块:

  1. 控制单元(Control Unit, CU)
  2. 算术逻辑单元(Arithmetic Logic Unit, ALU)
  3. 寄存器(Registers): pc, gpr, csr
  4. CLINT (Core-Local Interruptor): 参考 SiFive FE310-G002 芯片。
  5. 总线接口单元(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 中大的功能模块

  1. core
    1. 寄存器:pc,gpr,csr
    2. 取指:去 pc 指定的地址取指令,并把 pc 更新到下一条指令的起始地址
    3. 译码:解析指令,根据指令获取操作数以及运算的函数;执行阶段就是一行调用运算函数的代码
  2. 外设
    1. 存储器
    2. CLINT:其中包含了 timer
    3. uart
  3. bus:所有外设(片上外设、片外外设)都通过 bus 模块的接口进行访问
  4. loader:将程序加载到 memory

3.3 rust 工程的 crate & mod 结构

  1. 该工程使用 workspace 进行组织
  2. 将通过执行一条 add 指令来打通各个 mod 之间的接口
  3. 随着项目的深入,模块/接口可能会变化
├── 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 统一的错误处理

4.3 解码

4.4 测试

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容