尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

minirvEMU的实现

minirvEMU的实现
📅 发布时间:2026/7/12 1:32:45

minirvEMU的实现

本次实验通过C语言模拟了minirv的功能,并通过AM框架模拟外设进行测试.

下面进行详细介绍

  • 实现了lui jalr addi add sw lw sb lbu八条riscv指令
  • 实现了取指、译码、执行、更新PC等功能
  • 通过AM模拟外设进行验证

主要代码介绍

取值加译码模块

void instruction_fetch(){ int inst = M[PC>>2]; int opcode = inst & 0b00000000000000000111000001111111; if(inst == 0x00100073){ ebreak(inst); } switch(opcode){ case 0b00000000000000000000000000010011: addi(inst); break; case 0b00000000000000000000000001100111: jalr(inst); break; case 0b00000000000000000010000000000011: lw(inst); break; case 0b00000000000000000100000000000011: lbu(inst); break; case 0b00000000000000000010000000100011: sw(inst); break; case 0b00000000000000000000000000100011: sb(inst); break; default: break; } opcode = inst & 0b11111110000000000111000001111111; switch(opcode){ case 0b00000000000000000000000000110011: add(inst); break; default: break; } opcode = inst & 0b00000000000000000000000001111111; switch(opcode){ case 0b00000000000000000000000000110111: lui(inst); break; default: break; } }

指令执行模块

void reg_write(int addr, int val){ if(addr == 0) return; else R[addr] = val; } void addi(int inst){ int rd = (inst & 0b00000000000000000000111110000000) >> 7; int rs = (inst & 0b00000000000011111000000000000000) >> 15; int imm = (inst & 0b11111111111100000000000000000000) >> 20; imm = imm << 20 >> 20; reg_write(rd, R[rs] + imm); } void add(int inst){ int rd = (inst & 0b00000000000000000000111110000000) >> 7; int rs1 = (inst & 0b00000000000011111000000000000000) >> 15; int rs2 = (inst & 0b00000001111100000000000000000000) >> 20; reg_write(rd, R[rs1] + R[rs2]); } void lui(int inst){ int rd = (inst & 0b00000000000000000000111110000000) >> 7; int imm = (inst & 0b11111111111111111111000000000000) >> 12; imm = imm << 12; reg_write(rd, imm); } void lw(int inst){ int rd = (inst & 0b00000000000000000000111110000000) >> 7; int rs1 = (inst & 0b00000000000011111000000000000000) >> 15; int imm = (inst & 0b11111111111100000000000000000000) >> 20; imm = imm << 20 >> 20; int addr = (R[rs1] + imm) >> 2; reg_write(rd, ROM[addr]); } void lbu(int inst){ int rd = (inst & 0b00000000000000000000111110000000) >> 7; int rs1 = (inst & 0b00000000000011111000000000000000) >> 15; int imm = (inst & 0b11111111111100000000000000000000) >> 20; imm = imm << 20 >>20; uint32_t sel = (R[rs1] + (int)imm) & 0b11; uint32_t addr = (R[rs1] + (int)imm) >> 2; unsigned int val = (unsigned int)ROM[addr]; if(sel == 0) val = val % 256; else if(sel == 1){ val = val >> 8; val = val % 256; }else if(sel == 2){ val = val >> 16; val = val % 256; }else{ val = val >> 24; } reg_write(rd, val); } void sw(int inst){ int rs1 = (inst & 0b00000000000011111000000000000000) >> 15; int rs2 = (inst & 0b00000001111100000000000000000000) >> 20; int imm1 = (inst & 0b00000000000000000000111110000000) >> 7; int imm2 = (inst & 0b11111110000000000000000000000000) >> 25; int imm = (imm2 << 5) + imm1; imm = imm << 20 >> 20; uint32_t addr = (imm + R[rs1]); if(addr >= 0x20000000 && addr <= 0x20040000){ rgb[(addr-0x20000000) >> 2] = R[rs2]; } else{ addr = addr >> 2; ROM[addr] = R[rs2]; } } void sb(int inst){ int rs1 = (inst & 0b00000000000011111000000000000000) >> 15; int rs2 = (inst & 0b00000001111100000000000000000000) >> 20; int imm1 = (inst & 0b00000000000000000000111110000000) >> 7; int imm2 = (inst & 0b11111110000000000000000000000000) >> 25; int imm = (imm2 << 5) + imm1; imm = imm << 20 >> 20; uint32_t sel = (R[rs1] + imm) & 0b11; uint32_t addr = (R[rs1] + imm) >> 2; uint32_t temp = (uint32_t)ROM[addr]; uint32_t temp1 = temp & 0xff; uint32_t temp2 = (temp >> 8) & 0xff; uint32_t temp3 = (temp >> 16) & 0xff; uint32_t temp4 = temp >> 24; uint32_t val; if(sel == 0){ val = (temp4 << 24) + (temp3 << 16) + (temp2 << 8) +((uint32_t)R[rs2] & 0xff); }else if(sel == 1){ val = (temp4 << 24) + (temp3 << 16) + (((uint32_t)R[rs2] & 0xff) << 8) + temp1; }else if(sel == 2){ val = (temp4 << 24) + (((uint32_t)R[rs2] & 0xff) << 16) + (temp2 << 8) + temp1; }else if(sel == 3){ val = (((uint32_t)R[rs2] & 0xff) << 24) + (temp3 << 16) + (temp2 << 8) + temp1; } ROM[addr] = val; } void jalr(int inst){ int rd = (inst & 0b00000000000000000000111110000000) >> 7; int rs = (inst & 0b00000000000011111000000000000000) >> 15; uint32_t imm = (inst & 0b11111111111100000000000000000000) >> 20; imm = imm << 20 >> 20; int temp = PC; PC = imm + R[rs]; reg_write(rd, temp + 4); jalr_en = 1; } void output(int inst){ int rs = (inst & 0b00001100) >> 2; printf("R[%d]: %d\n", rs, R[rs]); } void ebreak(int inst){ if(R[10] == 0){ printf("HIT GOOD TRAP\n"); flag = 0; }else{ printf("HIT BAD TRAP\n"); flag = 0; } }

小技巧

imm = imm << 20 >>20;通过int特性进行符号拓展

寄存器写模块

void reg_write(uint_t addr, uint_t val){ if(addr == 0) return; else R[addr] = val; }

由于R[0]寄存器只能为0,故用此函数进行写操作
对寄存器进行操作多用uint32_t数据类型,uint32_t用于模仿寄存器
如

uint32_t temp = (uint32_t)ROM[addr]; uint32_t temp1 = temp & 0xff; uint32_t temp2 = (temp >> 8) & 0xff; uint32_t temp3 = (temp >> 16) & 0xff; uint32_t temp4 = temp >> 24; uint32_t val;

感觉很重要👇

不同intuint32_t
位宽位宽不固定由编译器/平台决定,可能16/32/64位标准强制32位
对负数右移是算数右移,符号拓展高位补0
溢出行为C标准是未定义行为,不同编译器结果随机模2³²自动环绕与硬件行为相同
输出printf(“%d”, val)printf(“inst = %“PRIx32”\n”, inst);

相关新闻

  • 降 AI 率最容易踩的 5 个坑!避开才能降到 15% 以下
  • 一文读懂 EMS 能量管理:能量调度、功率均衡核心机理详解
  • 监控网络交换机选型实战:200路H.265摄像机背板带宽与包转发率计算指南

最新新闻

  • Java调用C库:JNA 5分钟极速部署与实战指南
  • 辐射4 Ubuntu鼠标指针MOD制作教程:从素材提取到游戏界面美化
  • MoE模型训练稳定性:专家初始化与损失函数设计的关键作用
  • XLSX Workbench 与 ALV 对比:3种SAP数据导出方案选型指南
  • Java 数组全套精讲(定义、初始化、默认值、遍历、Arrays工具类、引用机制、方法传参)2026.7.11
  • 离散数学函数概念辨析:单射、满射、双射的3种判定方法与集合论基础

日新闻

  • IX9104 PCIe5.0 高速交换芯片@ACP#完整规格 + 应用场景总结
  • Unity游戏集成Coze智能体:实现NPC智能对话与知识库联动
  • SAP EPIC 建行回单查询:从标准类CL_EPIC_EXAMPLE_CN_CCB_GHTD到Z类的5处关键修改

周新闻

  • IX9104 PCIe5.0 高速交换芯片@ACP#完整规格 + 应用场景总结
  • Unity游戏集成Coze智能体:实现NPC智能对话与知识库联动
  • SAP EPIC 建行回单查询:从标准类CL_EPIC_EXAMPLE_CN_CCB_GHTD到Z类的5处关键修改

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号