当前位置: 首页 > news >正文

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

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

rv

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

特征:

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

应用程序接口

/* Memory access callbacks: data is input/output, return RV_BAD on fault, 0 otherwise */
typedef rv_res (*rv_store_cb)(void *user, rv_u32 addr, rv_u8 data);
typedef rv_res (*rv_load_cb)(void *user, rv_u32 addr, rv_u8 *data);/* Initialize CPU. */
void rv_init(rv *cpu, void *user, rv_load_cb load_cb, rv_store_cb store_cb);/* Single-step CPU. Returns 0 on success, one of RV_E* on exception. */
rv_u32 rv_step(rv *cpu);

用法

#include <stdio.h>
#include <string.h>#include "rv.h"rv_res load_cb(void *user, rv_u32 addr, rv_u8 *data) {if (addr - 0x80000000 > 0x10000) /* Reset vector is 0x80000000 */return RV_BAD;*data = ((rv_u8 *)(user))[addr - 0x80000000];return RV_OK;
}rv_res store_cb(void *user, rv_u32 addr, rv_u8 data) {if (addr - 0x80000000 > 0x10000)return RV_BAD;((rv_u8 *)(user))[addr - 0x80000000] = data;return RV_OK;
}rv_u32 program[2] = {/* _start: */0x02A88893, /* add a7, a7, 42 */0x00000073  /* ecall */
};int main(void) {rv_u8 mem[0x10000];rv cpu;rv_init(&cpu, (void *)mem, &load_cb, &store_cb);memcpy((void *)mem, (void *)program, sizeof(program));while (rv_step(&cpu) != RV_EECALL) {}printf("Environment call @ %08X: %u\n", cpu.pc, cpu.r[17]);return 0;
}

rv编译程序

使用 riscv-gnu-toolchain 工具链和 rv链接脚本。

建议使用gcc命令行:

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加载的二进制文件:

riscv64-unknown-elf-objcopy -g -O binary example.o example.bin

支持的指令列表

参见 支持指令列表。

公众号 | FunIO
微信搜一搜 “funio”,发现更多精彩内容。
个人博客 | blog.boringhex.top

http://www.lryc.cn/news/132916.html

相关文章:

  • 【从零学习python 】55.Python中的序列化和反序列化,JSON与pickle模块的应用
  • 【C++】详解内存中的堆和栈
  • QCustomPlot横坐标为毫秒级的时间轴数据展示的实时刷新数据功能
  • STM32/AT32 MCO管脚输出时钟配置
  • “SRP模型+”多技术融合在生态环境脆弱性评价模型构建、时空格局演变分析与RSEI 指数的生态质量评价
  • 【大虾送书第六期】搞懂大模型的智能基因,RLHF系统设计关键问答
  • 超越函数界限:探索JavaScript函数的无限可能
  • PHP实现轻量级WEB服务器接收HTTP提交的RFID刷卡信息并回应驱动读卡器显示播报语音
  • Neo4j之with基础
  • 60页数字政府智慧政务大数据资源平台项目可研方案PPT
  • 循环神经网络RNN完全解析:从基础理论到PyTorch实战
  • 【SA8295P 源码分析】52 - 答疑之 QNX 创建镜像、Android修改CMDLINE
  • 网络安全法律
  • Redis缓存问题(穿透, 击穿, 雪崩, 污染, 一致性)
  • 网络时代拟态环境的复杂化
  • 湘潭大学 湘大 XTU OJ 1055 整数分类 题解(非常详细)
  • 什么是视频的编码和解码
  • LeetCode 2681. Power of Heroes【排序,数学,贡献法】2060
  • AVL树的讲解
  • Unity 之 Input类
  • 亚信科技AntDB数据库连年入选《中国DBMS市场指南》代表厂商
  • AMBA总线协议(3)——AHB(一)
  • Git commit与pull的先后顺序
  • HarmonyOS/OpenHarmony应用开发-ArkTS语言渲染控制ForEach循环渲染
  • Powered by Paraverse | 平行云助力彼真科技打造演出“新物种”
  • 企微配置回调服务
  • 机器人远程控制软件设计
  • 面试题-React(二):React中的虚拟DOM是什么?
  • 分布式链路追踪——Dapper, a Large-Scale Distributed Systems Tracing Infrastructure
  • 【IEEE会议】第二届IEEE云计算、大数据应用与软件工程国际学术会议 (CBASE2023)