ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

只需3个函数就够了:rv核心API速查指南(rv_init / rv_step / rv_irq 快速上手清单)

只需3个函数就够了:rv核心API速查指南(rv_init / rv_step / rv_irq 快速上手清单) 只需3个函数就够了rv核心API速查指南rv_init / rv_step / rv_irq 快速上手清单【免费下载链接】rv32-bit RISC-V CPU in ~800 lines of C89项目地址: https://gitcode.com/gh_mirrors/rv/rvrv是一个用约 800 行 C89 代码实现的 32 位 RISC-V CPU 模拟器RV32IMAC完整支持 M 模式与 S 模式甚至可以直接引导启动 RISC-V 32 位 Linux。它的 API 设计极简rv_init、rv_step、rv_irq三个函数再加上你自己提供的一个内存回调就能在一台软件 CPU上跑起真实程序。本文是面向新手的 rv 核心 API 速查清单。rv 是什么先花 30 秒了解在写代码之前你需要知道 rv 的定位特性说明指令集RV32IMAC_Zicsr含原子、压缩、乘除法扩展特权级支持 M-mode 与 S-mode含完整 CSR 和 TLB代码量约 800 行 C89无内存分配无 64 位整数API2 个必调函数 1 个中断函数 1 个你写的内存回调战绩通过 riscv-tests 全部支持项可启动 RISC-V32 Linux核心文件只有两个接口定义在 rv.h全部实现在 rv.c。rv_init 初始化一行完成 CPU 复位void rv_init(rv *cpu, void *user, rv_bus_cb bus_cb);这是使用 rv 的第一步它做了三件事清零整个 CPU 状态——32 个通用寄存器r[32]、程序计数器、所有 CSR设置复位向量——PC 指向0x80000000RISC-V 惯例的 RAM 基址写入身份特征——设置misa寄存器声明支持 I/M/A/C 扩展和 U/S 模式初始特权级为 M-mode。两个参数怎么传user一个不透明指针会在每次内存访问时原样传回你的回调函数通常传内存数组的首地址bus_cb你自己实现的总线回调函数下文详解。 小技巧对同一个cpu再次调用rv_init就是一次完整的 CPU 复位调试死循环或挂死状态时非常有用。rv_step 单步执行模拟一颗软 CPU的心脏rv_u32 rv_step(rv *cpu);调用一次 CPU 执行一条指令。它内部完成取指含 C 扩展半字取指、译码、执行、访存全流程并自动累加cycle计数器处理页表翻译satp/TLB若mip有挂起中断按从高到低优先级自动响应见 rv.c 中的rv_service。返回值速查表返回值含义RV_TRAP_NONE正常执行完毕继续下一步RV_TRAP_WFI指令是wfi等待中断CPU 在此打盹RV_E*发生异常编码即 rv.h 中定义的异常号常用异常号一览完整列表见 rv.h宏编号场景RV_EBP3执行到ebreak断点RV_EMECALL11M-mode 执行ecall系统调用RV_ESECALL9S-mode 执行ecallRV_EILL2非法指令最常见的写法就是跑到 ecall 为止while (rv_step(cpu) ! RV_EMECALL) { }rv_irq 触发中断给 CPU 按响铃void rv_irq(rv *cpu, rv_cause cause);RISC-V 的中断不是立即打断执行的——rv_irq只是置位mip寄存器机器中断挂起真正响应发生在下一条rv_step中且需要对应mie使能位打开才会陷入。三种中断源宏值名称典型来源RV_CSI8Supervisor SoftwareSBI / OS 软件中断RV_CTI128Supervisor TimerCLINT 定时器到点RV_CEI512Supervisor ExternalPLIC 外部设备UART 等中断优先级由rv_service按编号从大到小扫描Timer External Software并根据mideleg决定陷入 S-mode 还是 M-mode。唯一的第四函数内存回调 rv_bus_cbrv 自己不管理内存所有读写都交给你的回调rv_res bus_cb(void *user, rv_u32 addr, rv_u8 *data, rv_u32 is_store, rv_u32 width);读从addr拷贝width字节到data写反向拷贝地址越界返回RV_BADrv 会将其转化为相应的 load/store fault 异常。完整可运行的最小示例在 tools/example/example.c一块 64KB 内存 2 条机器码add a7, a7, 42后接ecall约 30 行就把 CPU 跑起来了。编译它只需gcc -o example example.c rv.c。三个函数串起来完整执行循环rv cpu; rv_init(cpu, mem, bus_cb); /* 1. 复位 */ memcpy(mem, program, size); /* 加载程序到 0x80000000 */ for (;;) { rv_u32 res rv_step(cpu); /* 2. 执行一条指令 */ if (res RV_EMECALL) break; /* 3. 捕获系统调用 */ if (res RV_TRAP_WFI) /* 4. CPU 休眠时喂中断 */ rv_irq(cpu, RV_CTI); }这套init → step 循环 → irq 喂中断的骨架正是 tools/linux/mach.c 引导 Linux 的全部原理——配合 CLINT、PLIC、UART 三个小设备驱动同目录就能跑起真实的 RISC-V32 Linux文档见 tools/linux/README.md。新手上手清单✅ 定义一块内存数组 一个越界检查版bus_cb✅rv_init传入内存首地址✅ 把机器码 / 二进制镜像加载到0x80000000✅while循环里调用rv_step用返回值判断异常✅ 需要中断时wfi、定时器、UART调用rv_irq✅ 调试卡死重调rv_init复位或直接打印cpu.pc/cpu.csr.mepc总结rv 的 API 哲学就是CPU 状态全在一个rv结构体里你能做的只有初始化、单步、给中断。三个函数加一个回调约 800 行代码是你理解 RISC-V 指令执行、CSR、中断与页表机制的最佳入口。【免费下载链接】rv32-bit RISC-V CPU in ~800 lines of C89项目地址: https://gitcode.com/gh_mirrors/rv/rv创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表