谷动谷力

 找回密码
 立即注册
查看: 416|回复: 0
打印 上一主题 下一主题
收起左侧

600 行 ANSI C 代码实现 RISC-V CPU 核

[复制链接]
跳转到指定楼层
楼主
发表于 2023-8-24 19:00:07 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
600 行 ANSI C 代码实现 RISC-V CPU 核



今天在 GitHub 上看到一个 C 语言项目,用大约 600 行代码实现了一个 RISC-V CPU 核,甚为感叹,分享一下。不管是学习 C,还是学习 RISC-V,这个项目都有非常高的学习价值,开源万岁!


rv[1]

用 ANSI C 编写的 RISC-V CPU 内核。

特征:

  • RV32IMC 用户级实现
  • 通过 riscv 测试中所有支持的测试
  • ~600 行代码
  • 不使用任何大于 32 位的整数类型,即使对于乘法也是如此
  • 简单 API(两个函数,加上您提供的两个内存回调函数)
  • 无内存分配

应用程序接口
  1. /* Memory access callbacks: data is input/output, return RV_BAD on fault, 0 otherwise */
  2. typedef rv_res (*rv_store_cb)(void *user, rv_u32 addr, rv_u8 data);
  3. typedef rv_res (*rv_load_cb)(void *user, rv_u32 addr, rv_u8 *data);

  4. /* Initialize CPU. */
  5. void rv_init(rv *cpu, void *user, rv_load_cb load_cb, rv_store_cb store_cb);

  6. /* Single-step CPU. Returns 0 on success, one of RV_E* on exception. */
  7. rv_u32 rv_step(rv *cpu);
复制代码



用法
  1. #include <stdio.h>
  2. #include <string.h>

  3. #include "rv.h"

  4. rv_res load_cb(void *user, rv_u32 addr, rv_u8 *data) {
  5.   if (addr - 0x80000000 > 0x10000) /* Reset vector is 0x80000000 */
  6.     return RV_BAD;
  7.   *data = ((rv_u8 *)(user))[addr - 0x80000000];
  8.   return RV_OK;
  9. }

  10. rv_res store_cb(void *user, rv_u32 addr, rv_u8 data) {
  11.   if (addr - 0x80000000 > 0x10000)
  12.     return RV_BAD;
  13.   ((rv_u8 *)(user))[addr - 0x80000000] = data;
  14.   return RV_OK;
  15. }

  16. rv_u32 program[2] = {
  17.     /* _start: */
  18.     0x02A88893, /* add a7, a7, 42 */
  19.     0x00000073  /* ecall */
  20. };

  21. int main(void) {
  22.   rv_u8 mem[0x10000];
  23.   rv cpu;
  24.   rv_init(&cpu, (void *)mem, &load_cb, &store_cb);
  25.   memcpy((void *)mem, (void *)program, sizeof(program));
  26.   while (rv_step(&cpu) != RV_EECALL) {
  27.   }
  28.   printf("Environment call @ %08X: %u\n", cpu.pc, cpu.r[17]);
  29.   return 0;
  30. }
复制代码

为rv编译程序

使用 riscv-gnu-toolchain[2] 工具链和 rv 链接脚本[3]

建议使用gcc命令行:

  1. riscv64-unknown-elf-gcc example.S -nostdlib -nostartfiles -Tlink.ld -march=rv32imc -mabi=ilp32 -o example.o -e _start -g -no-pie
复制代码

然后用 obj 工具将0x80000000起始的二进制代码生成能被rv加载的二进制文件:

  1. riscv64-unknown-elf-objcopy -g -O binary example.o example.bin
复制代码


支持的指令列表

参见 支持指令列表[4]


参考资料
[1]rv: https://github.com/mnurzia/rv
[2]riscv-gnu-toolchain: https://github.com/riscv-collab/riscv-gnu-toolchain
[3]rv 链接脚本: https://github.com/mnurzia/rv/blob/main/tools/link.ld
[4]支持指令列表: https://github.com/mnurzia/rv#instruction-list

+10
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|深圳市光明谷科技有限公司|光明谷商城|Sunshine Silicon Corpporation ( 粤ICP备14060730号|Sitemap

GMT+8, 2024-5-19 10:28 , Processed in 0.075352 second(s), 41 queries .

Powered by Discuz! X3.2 Licensed

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表