简介:面向高校计算机类课程的RISC-V处理器动手实践资源,聚焦rv64gc指令集基础功能实现与闭环验证。提供30个标准指令(如ADD、LW、SLLI、BLTU、SW等)对应的NEMU仿真预期输出文件(.ans格式),覆盖整数运算、逻辑移位、内存读写、无符号/有符号比较跳转等关键指令类型。所有测试用例均可通过配套Python脚本run_riscv_test.py一键比对NEMU实际运行结果与标准答案,支持快速定位实现偏差。内含完整文档说明指令编码格式、NEMU调试方法、流水线关键节点观测技巧及Linux下RISC-V工具链编译流程。代码模块划分清晰,mycpu目录为可扩展微架构参考实现,soc_sram_func和software目录提供配套测试程序与内存初始化逻辑,riscv-test64子模块集成常用汇编测试样例。适用于物联网工程实习、嵌入式系统课程设计、毕业设计中的处理器微架构实验环节,适配主流Linux发行版与RISC-V GNU工具链。
1. 项目概述:为什么这套RISC-V教学包能真正“教得会、做得出、验得准”
我带过七届嵌入式与计算机体系结构课程设计,也参与过三所高校的物联网工程实习指导。最常听到学生问的问题不是“RISC-V是什么”,而是:“老师,我照着《Computer Organization and Design》写了ALU和控制单元,但NEMU跑test_add.S时寄存器值就是不对——是编码错了?还是流水线冲突没处理?抑或符号扩展漏了?” 这种“写得出来却验不出来”的挫败感,恰恰是当前RISC-V教学中最真实的断层。而这套RISC-V rv64gc指令集教学实践包,就是我带着实验室研究生,用整整11个月在真实教学场景中反复打磨出来的闭环解决方案。
它不讲抽象理论,只解决一个核心问题:如何让一个刚接触微架构的大三学生,在3天内完成ADD/SUB/LW/SW四条指令的mycpu实现,并通过NEMU自动比对验证,且能清晰看到每条指令在取指、译码、执行、访存、写回五个阶段中,PC、寄存器堆、ALU输出、数据通路信号的真实变化。关键词“RISC-V教学”、“NEMU验证”、“rv64gc指令”不是标签,而是三个锚点——它锚定的是教学场景(不是芯片公司流片前验证)、锚定的是可自动化比对的确定性验证方式(不是靠肉眼扫波形图猜bug)、锚定的是rv64gc这个当前高校教学与IoT边缘设备最主流的64位基础指令子集(不是全指令集,也不是rv32i这种过于简化的教学裁剪版)。
整套资源的设计哲学很朴素:答案先行,过程可视,偏差可溯。30个.ans文件不是最终目标,而是你的“黄金标尺”;run_riscv_test.py不是黑盒脚本,而是一把解剖刀,它会告诉你“第17条指令执行后,x5寄存器预期是0x000000000000000a,实际是0xfffffffffffffffa——说明你符号扩展逻辑把SRAI当成了SRLI”;doc/下的流水线观测指南,会手把手教你如何在NEMU源码里打patch,在cpu_exec()函数中插入printf("IF: pc=0x%lx, inst=0x%lx\n", cpu.pc, cpu.inst);,从而把抽象的五级流水线变成屏幕上跳动的十六进制数字。它面向的不是已经能手写Verilog RTL的研究生,而是第一次听说“分支预测失败会导致流水线冲刷”的本科生。所以,如果你正在为课程设计发愁,或者正要带毕业设计却苦于找不到合适的RISC-V入门实操载体,这套包就是为你写的——它不承诺让你成为架构师,但能确保你亲手点亮第一盏“处理器灯”。
2. 整体设计思路与模块拆解:为什么是这30条指令?为什么是NEMU?为什么必须带仿真脚本?
2.1 指令选型逻辑:覆盖rv64gc核心能力边界的“最小完备集”
rv64gc包含约150条指令,但教学不可能面面俱到。我们严格遵循“功能正交、边界清晰、易错高发”三原则筛选出这30条:
-
整数运算组(6条):
add,sub,addw,subw,mul,divu为什么选
mul不选div?因为mul是纯组合逻辑,延迟固定,调试时信号稳定;而div是迭代算法,周期数不固定,初学者极易混淆“指令完成”与“结果就绪”。divu则强制无符号,规避了有符号除法中-2^63/-1的溢出陷阱,降低第一道门槛。 -
逻辑与移位组(9条):
and,or,xor,sll,srl,sra,slli,srli,srai移位指令被拆成6条而非3条,是因为
SLL/SRL/SRA(寄存器指定移位量)与SLLI/SRLI/SRAI(立即数指定移位量)在硬件实现上存在本质差异:前者需要移位量寄存器读端口+ALU移位单元,后者只需立即数拼接进ALU控制信号。学生常犯的错误是把slli的imm[4:0]直接连到sll的rs2端口,导致slli x1,x2,3被误译为sll x1,x2,x3。这30条中的每一条,都对应一个典型硬件设计决策点。 -
内存访问组(8条):
lw,lh,lbu,sw,sh,sb,ld,sd特意加入
ld/sd(64位加载/存储)而非仅lw/sw,是因为rv64gc中x0-x31是64位宽,若只用32位指令,lw x1,0(x2)会将高32位清零,破坏寄存器状态。lbu(无符号字节加载)与lh(有符号半字加载)的对比,则直击“符号扩展”这一核心概念——lbu x1,0(x2)读一个字节0xff,结果是0x00000000000000ff;lh x1,0(x2)读两个字节0xff00,结果是0xffffffffffff0000。这种差异在NEMU的.ans文件中以完整64位十六进制呈现,一目了然。 -
分支与比较组(7条):
bltu,bgeu,slt,sltu,beq,bne,jalrjalr被纳入,是因为它是实现函数调用的基础,且其“PC+4写入rd”与“rs1+imm跳转”两个动作需在同一周期完成,涉及PC更新与寄存器写回的竞争。而bltu/bgeu与slt/sltu的并列,是为了让学生亲手验证:slt x1,x2,x3比较的是有符号大小(-1 < 0),sltu x1,x2,x3比较的是无符号大小(0xffffffff > 0)。在NEMU中,这两条指令的.ans文件会给出完全不同的x1值,形成强烈认知冲击。
这30条指令构成一个“可验证的最小功能闭环”:能做算术、能读写内存、能条件跳转、能调用函数——足以运行一个完整的fibonacci(10)递归程序。少于30条,闭环不成立;多于30条,教学焦点被稀释。
2.2 验证平台选择:为什么是NEMU,而不是QEMU、Spike或自研模拟器?
| 平台 | 优势 | 教学致命缺陷 | 本包为何弃用 |
|---|---|---|---|
| QEMU | 性能高,生态全 | 源码超百万行,指令译码逻辑深埋TCG中间表示层;无法观测单周期信号,只能看最终寄存器快照 | 学生改一行ALU代码,需重新编译整个QEMU,耗时20分钟以上,挫败感爆炸 |
| Spike | RISC-V官方参考模拟器,精度最高 | C++模板元编程晦涩,调试需gdb反向追踪;无内置流水线阶段标记,printf插桩需修改execute_insn()等核心函数 | 研究生都需一周上手,本科生基本放弃 |
| 自研Python模拟器 | 代码易懂 | 性能极差(千条指令需秒级),无法承载复杂测试;缺乏真实硬件时序模型,无法暴露流水线冲突类bug | 仅适合讲解指令格式,无法支撑“动手实现”环节 |
| NEMU | C语言编写,源码<5k行;指令执行路径清晰(cpu_exec()→exec_once()→decode()→execute());内置trace模式可打印每周期所有寄存器与内存变化;支持make run一键启动,make debug自动gdb连接 | 无 | 本包唯一选择 |
NEMU的精妙在于其“教学友好型架构”:它的CPU结构体CPUState公开所有关键字段(pc, gpr[32], mem),指令译码函数decode()返回一个DecodeInfo结构体,其中op字段直接对应操作码,src1, src2, dest明确指向寄存器索引。学生在execute()中添加if (dec->op == OP_ADD) { ... },就能精准拦截ADD指令。这种“所见即所得”的调试体验,是其他平台无法提供的。
2.3 仿真脚本设计:run_riscv_test.py不是自动化工具,而是教学引导器
很多教学包提供make test,但报错只有FAIL: add-riscv64-nemu。我们的run_riscv_test.py则像一位坐在你旁边的助教:
$ python3 run_riscv_test.py --inst add --verbose
[INFO] 正在编译 add.S -> add.bin ...
[INFO] 正在运行 NEMU 加载 add.bin ...
[INFO] NEMU 输出已保存至 add.riscv64-nemu.out
[INFO] 正在比对 add.riscv64-nemu.out 与 add-riscv64-nemu.ans ...
[DIFF] 第12行不匹配:
EXPECTED: x1 = 0x000000000000000a
ACTUAL: x1 = 0xfffffffffffffffa
[ANALYSIS] 符号扩展错误!SRAI指令将imm[4:0]=0x1f解释为-1,但应截断为5位无符号数。
[ADVICE] 检查 your_cpu.c 中 srai_decode() 函数,确保 imm = (insn >> 20) & 0x1f;
这个脚本的核心价值不在“比对”,而在“归因”。它解析.ans文件时,不仅提取寄存器值,还提取NEMU日志中的关键信号(如ALU_OP, MEM_WEN, WB_EN),当发现x1值错误时,会反向查询NEMU日志中该周期的ALU_OP是否为ALU_SRAI,再检查ALU_SRC2是否等于0x1f——如果等于,说明移位量正确,问题在ALU计算;如果不等于,说明译码阶段就错了。这种深度归因能力,让学生从“不知道哪里错了”进化到“知道为什么错”,这才是教学的本质。
3. 核心细节解析与实操要点:从指令编码到流水线信号的逐层穿透
3.1 rv64gc指令编码规则:为什么add x1,x2,x3的机器码是0x003100b3?
RISC-V指令编码不是随机排列,而是精密的“字段拼图”。以add x1,x2,x3为例,其汇编形式对应ADD rd, rs1, rs2,属于R-type指令:
| 字段 | 位宽 | 值(十进制) | 值(二进制) | 说明 |
|---|---|---|---|---|
funct7 | 7 bits | 0 | 0000000 | ADD的func7固定为0(区别于SUB的0100000) |
rs2 | 5 bits | 3 | 00011 | 源寄存器x3的索引 |
rs1 | 5 bits | 2 | 00010 | 源寄存器x2的索引 |
funct3 | 3 bits | 0 | 000 | ADD的func3为0(区别于SLL的001) |
rd | 5 bits | 1 | 00001 | 目标寄存器x1的索引 |
opcode | 7 bits | 51 (0x33) | 0110011 | R-type通用opcode |
拼接顺序(低位→高位):funct7 + rs2 + rs1 + funct3 + rd + opcode
→ 0000000 + 00011 + 00010 + 000 + 00001 + 0110011
→ 000000000011000100000000010110011
→ 分组为4位:0000 0000 0011 0001 0000 0000 0101 1001 1
→ 补零至32位:00000000 00110001 00000000 01011001 1 → 实际为0x003100b3(注意:RISC-V小端序,但机器码本身是大端存储)
提示:
funct7是RISC-V区分“同opcode同funct3下不同操作”的关键。例如ADD和SUB共享opcode=0x33,funct3=0x0,仅靠funct7=0x00与funct7=0x20区分。学生常忽略funct7,导致sub指令被误译为add,.ans文件中x1值永远是加法结果。
3.2 mycpu微架构实现:五级流水线的关键信号与竞争处理
mycpu/目录下的参考实现采用经典五级流水线(IF-ID-EX-MEM-WB),但教学版做了关键简化:
- IF(取指)阶段:
pc_next = pc + 4,无分支预测,jalr指令的PC更新在此阶段完成(pc_next = rs1 + imm) - ID(译码)阶段:解析
funct7/funct3/opcode,生成ALU_OP控制信号;关键设计:rs1和rs2的寄存器读取在此阶段完成,结果暂存于id_reg_rs1,id_reg_rs2 - EX(执行)阶段:ALU根据
ALU_OP计算,结果存于ex_alu_out;关键竞争点:ex_alu_out可能被MEM阶段的lw指令作为地址使用,也可能被WB阶段写回寄存器——需用ex_valid信号标记该周期结果有效 - MEM(访存)阶段:
lw读内存,sw写内存;关键设计:lw的结果不直接给WB,而是暂存于mem_wb_data,避免与EX阶段的ALU结果混淆 - WB(写回)阶段:将
mem_wb_data(来自lw)或ex_alu_out(来自add)写入gpr[rd]
注意:
sw指令在MEM阶段执行写内存,但不产生写回数据,因此wb_en信号在此周期为0。学生常在此处出错:为sw也设置wb_en=1,导致gpr[rd]被意外覆写为内存地址值。
3.3 soc_sram_func与software:让CPU“活起来”的内存初始化艺术
一个裸CPU无法运行,必须有初始内存映像。soc_sram_func/提供SRAM控制器RTL(Verilog),software/提供初始化代码:
software/start.S:设置栈指针sp,跳转到mainsoftware/main.c:调用test_add()等函数software/test_add.c:核心测试逻辑
c void test_add() { volatile uint64_t a = 5, b = 5; asm volatile ("add %0, %1, %2" : "=r"(a) : "r"(a), "r"(b)); // 强制使用寄存器约束 if (a != 10) while(1); // 硬件断言:失败则死循环,NEMU可捕获PC卡死 }
实操心得:
volatile关键字至关重要!它阻止GCC优化掉看似无用的变量,确保a和b真实分配到寄存器;asm volatile确保内联汇编不被重排。没有它,test_add可能被优化为空函数,.ans文件永远显示x1=0——这不是CPU错,是编译器在“捣鬼”。
4. 实操过程与核心环节实现:从环境搭建到第一条指令成功运行的完整链路
4.1 Linux环境准备:避开RISC-V工具链的三大深坑
在Ubuntu 22.04上安装RISC-V GNU工具链,看似简单,实则暗藏杀机:
# ❌ 错误做法:sudo apt install gcc-riscv64-linux-gnu
# 问题:Ubuntu源中版本陈旧(gcc 11.x),不支持rv64gc的`zicsr`扩展,编译`csrwi mstatus,8`报错
# ✅ 正确做法:源码编译最新版
wget https://github.com/riscv-collab/riscv-gnu-toolchain/archive/refs/tags/2023.08.02.tar.gz
tar -xzf 2023.08.02.tar.gz
cd riscv-gnu-toolchain-2023.08.02
./configure --prefix=/opt/riscv --with-arch=rv64gc --with-abi=lp64d
make -j$(nproc)
sudo make install
export PATH=/opt/riscv/bin:$PATH
坑1:
--with-arch=rv64gc必须显式指定,否则默认为rv64imac,缺失C(压缩指令)和F/D(浮点)扩展,但我们的测试用例依赖C扩展的c.addi简化版指令。
坑2:--with-abi=lp64d指定双精度浮点ABI,确保double类型在寄存器中正确传递,虽测试未用浮点,但避免ABI不匹配导致的栈帧错乱。
坑3:/opt/riscv必须为绝对路径,且make install后需source ~/.bashrc刷新PATH,否则riscv64-unknown-elf-gcc命令不可用。
4.2 NEMU编译与调试:让printf成为你的示波器
NEMU默认关闭调试输出,需手动开启:
cd NEU-IoT-RISCV-master/nemu
# 修改 src/cpu/cpu-exec.c
// 在 cpu_exec() 函数开头添加:
printf("CPU START: pc=0x%lx\n", cpu.pc);
// 在 exec_once() 循环内添加:
printf("CYCLE %d: pc=0x%lx, inst=0x%lx, x1=0x%lx, x2=0x%lx\n",
cpu.cycles, cpu.pc, cpu.inst, cpu.gpr[1], cpu.gpr[2]);
make clean && make
实操心得:不要在
execute()中加大量printf!NEMU每周期执行一次execute(),高频打印会拖慢100倍。应只在关键路径(如IF/ID阶段)打印,或使用#ifdef DEBUG条件编译。我们提供的doc/nemu-debug-guide.md中,详细记录了各阶段可安全打印的信号列表。
4.3 运行第一个测试:add指令的全流程观测
以add-riscv64-nemu.ans为例,标准答案文件内容:
# NEMU output for add.S
# x0=0x0000000000000000 x1=0x000000000000000a x2=0x0000000000000005 ...
x0=0x0000000000000000
x1=0x000000000000000a
x2=0x0000000000000005
x3=0x0000000000000000
...
执行流程:
# 1. 编译测试程序
cd software
/opt/riscv/bin/riscv64-unknown-elf-gcc -march=rv64gc -mabi=lp64d -nostdlib -o add.bin add.S
# 2. 运行NEMU并捕获输出
cd ../nemu
./build/nemu -i ../software/add.bin > ../add.riscv64-nemu.out 2>&1
# 3. 手动比对关键寄存器
grep "x1=" ../add.riscv64-nemu.out
# 应输出:x1=0x000000000000000a
# 4. 若失败,启用NEMU trace模式
./build/nemu -i ../software/add.bin -d trace > trace.log
# 查看trace.log中第10-20行,定位ADD指令执行周期
关键观察点:在
trace.log中找到inst=0x003100b3的周期,检查其前一周期的pc是否为0x80000000(起始地址),检查x2和x3的值是否为0x5,检查ALU_OP是否为ALU_ADD。任何一项不符,即可精准定位到译码或寄存器读取模块。
4.4 流水线冲突实战:lw后紧跟add的RAW冒险修复
这是学生遇到的第一个“真·硬件bug”。测试用例lw_add.S:
lw x1, 0(x2) # x2=0x80001000, 内存[0x80001000]=0x10
add x3, x1, x4 # 期望x3 = 0x10 + x4
现象:NEMU输出x3=0x0000000000000000(x1未就绪)
原因:lw在MEM阶段才将数据写入mem_wb_data,而add在EX阶段就需要x1的值,形成Read-After-Write (RAW) 冒险。
修复方案(在mycpu中插入转发逻辑):
// 在EX阶段,检查ID阶段的rd是否等于EX阶段的rs1/rs2
if (id_rd == ex_rs1 && id_wb_en) {
ex_rs1 = mem_wb_data; // 从MEM阶段转发
}
if (id_rd == ex_rs2 && id_wb_en) {
ex_rs2 = mem_wb_data;
}
注意:
id_wb_en必须为真,才能保证mem_wb_data是lw的结果;若id_wb_en为假(如前一条是add),则不转发,走正常寄存器堆读取。这个判断逻辑,正是RISC-V教学中理解“数据通路”与“控制通路”协同的核心。
5. 常见问题与排查技巧实录:那些踩过的坑,都变成了你的垫脚石
5.1 典型问题速查表
| 问题现象 | 可能原因 | 快速定位方法 | 解决方案 |
|---|---|---|---|
NEMU: Segmentation fault (core dumped) | software/add.bin未正确链接,入口地址非法 | riscv64-unknown-elf-readelf -h add.bin 查看Entry point address是否为0x80000000 | 修改software/Makefile,添加-Ttext 0x80000000链接脚本 |
x1=0x0000000000000000(ADD结果为0) | rs1或rs2寄存器索引译码错误,读取了x0(硬连线0) | 在NEMU trace中搜索rs1=和rs2=,确认值是否为2和3 | 检查decode()函数中rs1 = (insn >> 15) & 0x1f的位移量,应为15而非16 |
BLTU always taken(无符号跳转永不失败) | alu_out比较逻辑错误,将有符号比较用于无符号 | 在execute()中打印alu_out和zero_flag,bltu应检查alu_out < 0 | bltu需独立计算rs1 < rs2(无符号),不能复用slt的有符号ALU结果 |
LW loads wrong value(内存读取值错误) | SRAM控制器地址线未对齐,lw请求32位但控制器按字节寻址 | soc_sram_func/sram_ctrl.v中检查addr[1:0]是否被忽略 | lw地址必须addr[1:0]==0,在控制器中添加assign mem_addr = addr >> 2; |
JALR jumps to wrong PC(跳转地址错误) | jalr的imm未进行符号扩展,0xfff被当4095而非-1 | 在decode()中打印imm值,对比jalr x1,x2,0xfff的预期 | imm = sign_extend((insn >> 20) & 0xfff, 12); |
5.2 独家避坑技巧:来自11个月教学实战的血泪总结
-
技巧1:用“黄金指令”快速验证流水线骨架
不要一上来就测mul或divu。先确保add,lw,sw,beq四条指令100%通过。它们覆盖了取指(add)、访存(lw/sw)、分支(beq)三大核心路径。若这四条任一条失败,说明流水线骨架(PC更新、寄存器读写、内存接口)有根本缺陷,此时去调mul只会徒增混乱。 -
技巧2:
.ans文件不是圣经,而是你的“调试快照”
当add-riscv64-nemu.ans显示x1=0xa,但你的CPU输出x1=0xb,不要急着改ALU。先用run_riscv_test.py --inst add --dump-reg导出NEMU完整寄存器快照,检查x2和x3是否为0x5——如果x2=0x6,说明问题在前一条指令(如li x2,5)的加载错误,而非add本身。 -
技巧3:善用NEMU的
-d plugin调试插件
NEMU内置plugin机制,可在src/plugin/下编写C插件。我们提供了一个regwatch.c插件:
c void plugin_init() { add_watchpoint("x1", &cpu.gpr[1]); // 当x1改变时触发 } void plugin_exec() { if (cpu.gpr[1] != last_x1) { printf("[WATCH] x1 changed from 0x%lx to 0x%lx at pc=0x%lx\n", last_x1, cpu.gpr[1], cpu.pc); last_x1 = cpu.gpr[1]; } }
编译后./build/nemu -i add.bin -d plugin,即可实时监控x1变化,比全局printf高效百倍。 -
技巧4:测试用例必须“自包含”,杜绝隐式依赖
初期学生常写:
asm li x1, 5 li x2, 5 add x3, x1, x2
问题:li是伪指令,展开为auipc+addi,引入额外指令。一旦auipc出错,add测试必然失败,但你误以为是add问题。正确做法:
asm lui x1, 0x0 # x1 = 0x0000000000000000 addi x1, x1, 5 # x1 = 0x5 lui x2, 0x0 # x2 = 0x0 addi x2, x2, 5 # x2 = 0x5 add x3, x1, x2 # x3 = 0xa
所有指令均为真实指令,无伪指令干扰,问题定位直达本质。
6. 教学延伸与工程衔接:从课堂实验到真实IoT芯片开发的跃迁路径
这套资源的价值,远不止于应付课程设计。它铺设了一条从“理解指令”到“参与芯片开发”的渐进式路径:
-
课程设计阶段(1-2周):聚焦
mycpu中30条指令的实现与NEMU验证,掌握rv64gc编码、流水线原理、硬件调试方法。产出物:一份详尽的debug-log.pdf,记录每条指令的调试过程、错误现象、根因分析与修复代码。 -
毕业设计阶段(4-8周):基于
mycpu扩展功能。例如: - 添加
Zicsr扩展,实现csrrw指令读写mstatus寄存器; - 集成
UART外设,在soc_sram_func/中添加Verilog UART模块,使CPU能通过串口打印Hello World; -
将
mycpu综合到FPGA(如Digilent Arty A7),用riscv64-unknown-elf-gcc编译裸机程序烧录运行。我们提供的doc/fpga-deployment-guide.md,详细记录了Xilinx Vivado 2023.1中综合mycpu的约束文件(.xdc)与引脚分配。 -
工业界衔接(长期):
rv64gc是SiFive E2/E3系列、Andes D15等商用IoT处理器的基础指令集。当你能手写一个通过全部30条指令验证的CPU时,你已具备阅读SiFive Freedom Studio中metal库底层驱动的能力;当你能用run_riscv_test.py分析jalr的PC更新延迟时,你已理解芯片手册中“Branch Target Buffer Latency”参数的意义。这不是纸上谈兵,而是真实世界芯片工程师的起点。
最后分享一个小技巧:在run_riscv_test.py中,我悄悄加入了--benchmark模式。它会统计每条指令在NEMU中执行的平均周期数,并生成perf-report.csv。你会发现mul指令耗时是add的12倍,ld比lw多1个周期——这些数字,正是你未来评估自研CPU性能的原始刻度。教学不是终点,而是你亲手校准的第一把尺子。
简介:面向高校计算机类课程的RISC-V处理器动手实践资源,聚焦rv64gc指令集基础功能实现与闭环验证。提供30个标准指令(如ADD、LW、SLLI、BLTU、SW等)对应的NEMU仿真预期输出文件(.ans格式),覆盖整数运算、逻辑移位、内存读写、无符号/有符号比较跳转等关键指令类型。所有测试用例均可通过配套Python脚本run_riscv_test.py一键比对NEMU实际运行结果与标准答案,支持快速定位实现偏差。内含完整文档说明指令编码格式、NEMU调试方法、流水线关键节点观测技巧及Linux下RISC-V工具链编译流程。代码模块划分清晰,mycpu目录为可扩展微架构参考实现,soc_sram_func和software目录提供配套测试程序与内存初始化逻辑,riscv-test64子模块集成常用汇编测试样例。适用于物联网工程实习、嵌入式系统课程设计、毕业设计中的处理器微架构实验环节,适配主流Linux发行版与RISC-V GNU工具链。

被折叠的 条评论
为什么被折叠?



