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

minirvEMU的实现

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);
http://www.jsqmd.com/news/1170912/

相关文章:

  • 告别AI黑话焦虑!从入门到进阶,一口气读懂LLM、Token、Context、MCP全术语
  • 5分钟搞定足球经理头像配置:NewGAN-Manager开源工具完全指南
  • Visual Studio 2022 调试反编译:3步配置.NET/Unity DLL源码实时查看
  • WGAN-GP与区域法:高效生成动态安全域边界的工程实践
  • 自媒体必备!超逼真AI配音,zmaiFy解决出海痛点
  • 监控网络交换机选型实战:200路H.265摄像机背板带宽与包转发率计算指南
  • GPT 并不会检索事实;它只是依托语言模式,生成听起来理应正确的文本,而这些语言模式有时会让模型出现谬误。
  • 一文读懂 EMS 能量管理:能量调度、功率均衡核心机理详解
  • L9958与PIC18LF4620的电机控制方案设计与优化
  • 保研机试 43 校真题分析:LeetCode 与 OJ 平台 5 大高频考点与权重
  • 移远EC20/EC200T 4G模块PPP拨号实战:Ubuntu 16.04下5步完成网络配置与DNS修复
  • 数字人带货不做直播先起号,一个月要准备哪些钱?脚本、出片、投流、改稿四笔预算漏一笔都会算偏
  • ENVI 5.6 高分一号影像几何精纠正:30个GCP点RMS误差≤0.5像元实战
  • 3分钟上手QtScrcpy:在电脑上流畅控制安卓手机的终极指南
  • C/C++ 保留小数全攻略:从printf到setprecision
  • 时序图 vs 协作图:5个维度对比分析微服务间 API 调用交互
  • Unity Shader遮罩实战:从原理到新手引导与特效实现
  • DeepSeek深度思考模式到底多强?实测对比LLaMA-3、GPT-4在复杂推理任务中准确率提升47.6%
  • 22道AI‑Agent高频面试题整理,吃透轻松拿下offer
  • 机器视觉精度误区解析:4倍与10倍像素精度规则的应用场景对比
  • 如何快速解决Windows运行库问题:完整的一键式VisualCppRedist AIO终极指南
  • 隧道磁阻 (TMR) 传感器 芯片设计级原理 + 行业量产最佳实现全路径
  • 3步掌握QMCDecode:彻底解决Mac音频格式兼容问题的完整方案
  • 从零实现C++ JSON解析器:递归下降、内存管理与API设计实战
  • 无线充电4种补偿结构(SS/SP/PS/PP)对比:恒压/恒流特性与ZPA条件分析
  • 制造业文件数据管理的需求分析与方案评估
  • 长江宜宾段洪峰明日凌晨2时过境
  • Windows Console API 实战:C++ 飞机大战游戏实现 3 大核心模块解析
  • Makefile 设计:避免 make clean 误删的 2 种安全模式与 .PHONY 声明
  • Cocos2d-x中Spine动画内存泄露排查与修复实战