QtRVSim(二)一个 RISC-V 程序的解码流程

继上一篇文章简单代码分析后,本文主要调研如何实现对指令的解析运行。

调试配置

使用 gdb 工具跟踪调试运行。

image-20240124233037109

c_cpp_properties.json 项目配置:

{"name": "QtRvSim","includePath": ["${workspaceFolder}/**"],"defines": [],"compilerPath": "/usr/bin/clang","cStandard": "c11","cppStandard": "c++17","intelliSenseMode": "gcc-x64","configurationProvider": "ms-vscode.cmake-tools"}

launch.json:

{// 使用 IntelliSense 了解相关属性。 // 悬停以查看现有属性的描述。`                                                          // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387"version": "0.2.0","configurations": [{"name": "(gdb) Launch","type": "cppdbg","request": "launch",// "program": "${fileDirname}/${fileBasenameNoExtension}","program": "${command:cmake.launchTargetPath}","args": ["/home/jingqing3948/Develop/qtrvsim-test/sum2vars-riscv"],"stopAtEntry": false,"cwd": "${workspaceFolder}","environment": [{"name": "PATH","value":"${env:PATH):${command:cmake.getLaunchTargetDirectory]"}],"externalConsole": true,"MIMode": "gdb","setupCommands": [{"description": "Enable pretty-printing for gdb","text": "-enable-pretty-printing","ignoreFailures": true}],//"preLaunchTask": "Tutorial",  "miDebuggerPath": "/usr/bin/gdb"}]
}

程序解析流程

由于我的毕设任务主要是实现 F 扩展,因此我集中精力于对于指令集的解码、执行、写回过程,对于取指过程不同扩展区别不大暂不过多关注。

程序执行流程跟踪分析:

//main.cppint main(int argc, char *argv[]) {//省略一系列预配置,在 machine.play() 函数中执行程序machine.play();}
void Machine::play() {//set status//start execute each instructionsstep_internal(true);
}void Machine::step_internal(bool skip_break) {//set statustry {QTime start_time = QTime::currentTime();do {//execute one step cr->step(skip_break);} while (time_chunk != 0 && stat == ST_BUSY && !skip_break&& start_time.msecsTo(QTime::currentTime()) < (int)time_chunk);} catch (SimulatorException &e) {//set trapped status}if (regs->read_pc() >= program_end) {//set exit status} else {//set status as the previous status}
}
//core.cpp//step(): wrapper of do_step() function
void Core::step(bool skip_break) {//pcstate.cycle_count++;do_step(skip_break);emit step_done(state);
}void CoreSingle::do_step(bool skip_break) {Pipeline &p = state.pipeline;p.fetch = fetch(pc_if, skip_break);p.decode = decode(p.fetch.final);p.execute = execute(p.decode.final);p.memory = memory(p.execute.final);p.writeback = writeback(p.memory.final);regs->write_pc(mem_wb.computed_next_inst_addr);if (mem_wb.excause != EXCAUSE_NONE) {handle_exception(mem_wb.excause, mem_wb.inst, mem_wb.inst_addr, regs->read_pc(), prev_inst_addr,mem_wb.mem_addr);return;}prev_inst_addr = mem_wb.inst_addr;
}

由此可见,对于F扩展的实现,除去新硬件的实现,主要需要补充的就是 Pipeline.decode() , Pipeline.execute() , Pipeline.memory() , Pipeline.writeback() 以上内容。

首先我需要先实现 F 指令集的 decode。单条指令解码由

//core.cppDecodeState Core::decode(const FetchInterstage &dt) {InstructionFlags flags;bool w_operation = this->xlen != Xlen::_64;AluCombinedOp alu_op {};AccessControl mem_ctl;ExceptionCause excause = dt.excause;// decode后把结果存在flags alu_op mem_ctl结构体里,也就是说指令解码具体实现由 instructions.cpp 的 flags_alu_op_mem_ctl 函数实现dt.inst.flags_alu_op_mem_ctl(flags, alu_op, mem_ctl);//flags结构体通过位域操作识别rs rd op等信息,并返回
}
//instructions.cppvoid Instruction::flags_alu_op_mem_ctl(InstructionFlags &flags,AluCombinedOp &alu_op,AccessControl &mem_ctl) const {//通过 InstructionMapFind 函数查找指令表const struct InstructionMap &im = InstructionMapFind(dt);flags = (enum InstructionFlags)im.flags;alu_op = im.alu;mem_ctl = im.mem_ctl;
}static inline const struct InstructionMap &InstructionMapFind(uint32_t code) {const struct InstructionMap *im = &C_inst_map[instruction_map_opcode_field.decode(code)];//递归解码,和指令集在程序中的存储方式有关while (im->subclass != nullptr) {im = &im->subclass[im->subfield.decode(code)];}if ((code ^ im->code) & im->mask) {return C_inst_unknown;}return *im;
}

也就是说对于一条指令,首先需要根据 instruction_map_opcode_field.decode(code) 判断其操作码类型,然后用对应操作码的解码表 C_inst_map 元素进行解码。并且解码是递归进行的,因为解码表的存储方式是递归存储(先大类后小类,比如 I_inst_map 下的 load 指令全部属于 LOAD_map ,包括 lb lh lw 等。)

C_inst_map 解码表目前只包含了 i 扩展的指令集,对于 F 扩展实现从 C_inst_map 开始参照 I 扩展逐层实现。

static const struct InstructionMap C_inst_map[] = {IM_UNKNOWN,IM_UNKNOWN,IM_UNKNOWN,{"i", IT_UNKNOWN, NOALU, NOMEM, I_inst_map, {}, 0x3, 0x3, { .subfield = {5, 2} }, nullptr},
};static const struct InstructionMap I_inst_map[] = {{"load", IT_I, NOALU, NOMEM, LOAD_map, {}, 0x03, 0x7f, { .subfield = {3, 12} }, nullptr}, // LOADIM_UNKNOWN, // LOAD-FPIM_UNKNOWN, // custom-0{"misc-mem", IT_I, NOALU, NOMEM, MISC_MEM_map, {}, 0x0f, 0x7f, { .subfield = {3, 12} }, nullptr}, // MISC-MEM{"op-imm", IT_I, NOALU, NOMEM, OP_IMM_map, {}, 0x13, 0x7f, { .subfield = {3, 12} }, nullptr}, // OP-IMM{"auipc", IT_U, { .alu_op=AluOp::ADD }, NOMEM, nullptr, {"d", "u"}, 0x17, 0x7f, { .flags = IMF_SUPPORTED | IMF_ALUSRC | IMF_REGWRITE | IMF_PC_TO_ALU }, nullptr}, // AUIPC{"op-imm-32", IT_I, NOALU, NOMEM, OP_IMM_32_map, {}, 0x1b, 0x7f, { .subfield = {3, 12} }, nullptr}, // OP-IMM-32    IM_UNKNOWN, // OP-IMM-32IM_UNKNOWN, // 48b{"store", IT_I, NOALU, NOMEM, STORE_map, {}, 0x23, 0x7f, { .subfield = {3, 12} }, nullptr}, // STOREIM_UNKNOWN, // STORE-FPIM_UNKNOWN, // custom-1{"amo", IT_R, NOALU, NOMEM, AMO_map, {}, 0x2f, 0x7f, { .subfield = {3, 12} }, nullptr}, // OP-32{"op", IT_R, NOALU, NOMEM, OP_map, {}, 0x33, 0x7f, { .subfield = {1, 25} }, nullptr}, // OP{"lui", IT_U, { .alu_op=AluOp::ADD }, NOMEM, nullptr, {"d", "u"}, 0x37, 0x7f, { .flags = IMF_SUPPORTED | IMF_ALUSRC | IMF_REGWRITE }, nullptr}, // LUI{"op-32", IT_R, NOALU, NOMEM, OP_32_map, {}, 0x3b, 0x7f, { .subfield = {1, 25} }, nullptr}, // OP-32IM_UNKNOWN, // 64bIM_UNKNOWN, // MADDIM_UNKNOWN, // MSUBIM_UNKNOWN, // NMSUBIM_UNKNOWN, // NMADDIM_UNKNOWN, // OP-FPIM_UNKNOWN, // reservedIM_UNKNOWN, // custom-2/rv128IM_UNKNOWN, // 48b{"branch", IT_B, NOALU, NOMEM, BRANCH_map, {}, 0x63, 0x7f, { .subfield = {3, 12} }, nullptr}, // BRANCH{"jalr", IT_I, { .alu_op=AluOp::ADD }, NOMEM, nullptr, {"d", "o(s)"}, 0x67, 0x7f, { .flags =
IMF_SUPPORTED | IMF_REGWRITE | IMF_BRANCH_JALR | IMF_ALUSRC | IMF_ALU_REQ_RS }, inst_aliases_jalr}, // JALRIM_UNKNOWN, // reserved{"jal", IT_J, { .alu_op=AluOp::ADD }, NOMEM, nullptr, {"d", "a"}, 0x6f, 0x7f, { .flags =
IMF_SUPPORTED |
IMF_REGWRITE | IMF_JUMP | IMF_PC_TO_ALU | IMF_ALUSRC }, inst_aliases_jal}, // JAL{"system", IT_I, NOALU, NOMEM, SYSTEM_map, {}, 0x73, 0x7f, { .subfield = {3, 12} }, nullptr}, // SYSTEMIM_UNKNOWN, // reservedIM_UNKNOWN, // custom-3/rv128IM_UNKNOWN, // >= 80b
};

下一步目标:从最基础的 F load, F store 指令开始实现。先达成能成功识别指令的目标。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/649500.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【微调大模型】如何利用开源大模型,微调出一个自己大模型

在人工智能的浪潮中,深度学习已经成为了最炙手可热的技术。其中,预训练大模型如Transformer、BERT等,凭借其强大的表示能力和泛化能力,在自然语言处理、计算机视觉等多个领域取得了显著的成功。然而,这些预训练大模型往往需要巨大的计算资源和时间成本,对于一般的研究者或…

Spring5系列学习文章分享---第五篇(事务概念+特性+案例+注解声明式事务管理+参数详解 )

目录 事务事务概念什么是事务事务四个特性&#xff08;ACID&#xff09; 搭建事务操作环境Spring 事务管理介绍注解声明式事务管理声明式事务管理参数配置XML 声明式事务管理事务操作&#xff08;完全注解声明式事务管理&#xff09;感谢阅读 开篇: 欢迎再次来到 Spring 5 学习…

Lowest Common Ancestor

模板 1. Tarjan 一个讲的很好的视频&#xff1a;D10 Tarjan算法 P3379【模板】最近公共祖先&#xff08;LCA&#xff09;_哔哩哔哩_bilibili&#xff0c;董晓算法出品。 Tarjan总体来说可以概括为&#xff1a; 记录访达&#xff1a;记录某个节点是否已经访问过&#xff0c;防…

3. MATLAB中Plot绘制放大特定的区域

在MATLAB中&#xff0c;我们经常需要绘制图形并进行一些自定义的操作。在本示例中&#xff0c;我们将演示如何在MATLAB中绘制一个图形&#xff0c;并通过放大某个特定的区域来突出显示。 ## 原始图形 首先&#xff0c;我们绘制了一个包含正弦和余弦函数的图形。 % MATLAB 代…

RabbitMQ 笔记二

1.Spring 整合RabbitMQ 生产者消费者 创建生产者工程添加依赖配置整合编写代码发送消息 创建消费者工程添加依赖配置整合编写消息监听器 2.创建工程RabbitMQ Producers spring-rabbitmq-producers <?xml version"1.0" encoding"UTF-8"?> <pr…

【计算机图形学】实验五 一个简单的交互式绘图系统(实验报告分析+截图+源码)

可以先看一看这篇呀~【计算机图形学】专栏前言-CSDN博客https://blog.csdn.net/m0_55931547/article/details/135863062 目录 一、实验目的 二、实验内容

77 C++对象模型探索。虚函数- 从静态联编,动态联编出发,分析 虚函数调用问题探究

什么叫做单纯的类&#xff1a; 比较简单的类&#xff0c;尤其不包括 虚函数 和虚基类。 什么叫不单纯的类&#xff1a; 从上一章的学习我们知道&#xff0c;在某些情况下&#xff0c;编译器会往类内部增加一些我们看不见但是真实存在的成员变量&#xff0c;例如vptr&#xff…

unitary MUSIC 算法

unitary MUSIC 算法 论文 A Unitary Transformation Method for Angle-of-Arrival Estimation 中提出了 unitary MUSIC 的算法&#xff0c;直译就是酉 MUSIC 算法&#xff0c;即酉变换 MUSIC 算法。该算法的目的是简化计算复杂度&#xff0c;将传统 MUSIC 算法中的复数 SVD 和复…

【shell-10】shell实现的各种kafka脚本

kafka-shell工具 背景日志 log一.启动kafka->(start-kafka)二.停止kafka->(stop-kafka)三.创建topic->(create-topic)四.删除topic->(delete-topic)五.获取topic列表->(list-topic)六. 将文件数据 录入到kafka->(file-to-kafka)七.将kafka数据 下载到文件-&g…

Linux内核中USB设备驱动实现

USB 设备驱动&#xff1a; 一、USB 描述符&#xff1a;&#xff08;存在于USB 的E2PROM里面&#xff09; 1、 设备描述符&#xff1a;struct usb_device_descriptor 2、 配置描述符&#xff1a;struct usb_config_descriptor 3、 接口描述符&#xff1a;struct usb_interfa…

linux深度学习开发基础命令——极简版

linux深度学习开发基础命令——极简版 本博客只是阐述常用的部分shell命令&#xff0c;更为全面的内容请参考其他博客 1. 创建python虚拟环境 默认使用conda创建 conda create -yourenv_name pyhton3.x 查看全部虚拟环境 conda env list 激活虚拟环境 conda activate env_name …

GO——GPM

参考&#xff1a;https://juejin.cn/post/6844904130398404616 并发模型 参考&#xff1a;https://zhuanlan.zhihu.com/p/137339439 多进程 要点 主进程监听每进来一个请求&#xff0c;fork子进程处理 缺点 进程占用高&#xff0c;服务器负载高进程间通信困难 参考&#xff…

2024 CKA 题库 | 15、备份还原 etcd

不等更新题库 文章目录 15、备份还原 etcd题目:考点&#xff1a;参考链接:解答:备份快照恢复快照 检查 15、备份还原 etcd 题目: 设置配置环境 此项目无需更改配置环境。但是&#xff0c;在执行此项目之前&#xff0c;请确保您已返回初始节点。 [candidatemaster01] $ exit #…

【Deeplabv3+】Ubutu18.04中使用pytorch复现Deeplabv3+第三步)-----CityscapesScripts生成自己的标签

本文是在前面两篇文章的基础上&#xff0c;讲解如何更改训练数据集颜色&#xff0c;需要与前面两篇文章连起来看。 本文用于修改cityscapes数据集的标签颜色与Semankitti数据集的标签一致&#xff0c;对修改后的数据集进行训练。需要下载两个开发工具包和一个数据集&#xff0…

Git标签推送

标签默认属于本地分支&#xff0c;推送分支的时候并不会上传。需要自己手动推送 通过命令 git push origin <tagname>推送指定的标签 通过命令git push origin --tags批量推送所有的标签 在VS里打开git命令行窗口的方法&#xff1a;Git更改-操作-打开命令行提示符 对于…

1.19信息学,信息熵(wordle)

所谓均方误差实际上就是方差 分析&#xff1a;对单词进行编码后&#xff0c;采用聚类方法&#xff0c;可以将单词难度分为三类或者更多&#xff0c;如困难、一般、简单。然后对每一类的单词可视化分析&#xff0c;并描述数据得出结论。 聚类算法较多&#xff0c;在论文中可以…

Docker镜像

创建镜像有三种方法&#xff0c;分别为基于已有镜像创建、基于本地模板创建以及基于Dockerfile创建。 基于现有镜像创建 首先启动一个镜像&#xff0c;在容器里做修改 然后将修改后的容器提交为新的镜像&#xff0c;需要使用该容器的 ID 号创建新镜像 常用选项&#xff1a; -…

【Unity】【游戏开发】Pico打包后项目出现运行时错误如何Debug

【背景】 开发过程中的报错可以通过控制台查看&#xff0c;但是PICO项目这类依赖特定设备环境的应用往往存在打包后在设备端发生运行时错误。这时如何能查看到Debug信息呢&#xff1f; 【分析】 Pico也是安卓系统&#xff0c;所以这个问题就可以泛化为Unity有哪些在安卓端运…

Linux系统中编写bash脚本进行mysql的数据同步

一、为何要用脚本做数据同步 &#xff08;一&#xff09;、问题 我们的视频监控平台云服务器&#xff0c;需要向上级的服务器定期同步一些数据表的数据&#xff0c;前期做了个程序&#xff0c;可以实现同步。但是&#xff0c;现在数据库的结构改了&#xff0c;结果又需要该程序…

C++实现推箱子游戏

推箱子游戏 运行之后的效果如视频所示&#xff0c;在完成游戏后播放音乐 准备工作&#xff1a;建立一个新的文件夹&#xff0c;并在文件夹中任意增加一张背景图片&#xff0c;以及各个部件的照片文件 因为这里用到了贴图技术&#xff0c;要使用graphic.h这个函数&#xff0c…