从零开始学RISC-V之CSR访问
文章目录
- 背景介绍
- 开始Coding
- 指令译码
- 算术运算
- 测试程序
- 仿真结果及分析
背景介绍
CSR,即Control and Status Register,控制与状态寄存器,属于CPU自带的一类寄存器(注意这里需要跟前文所述的通用数据寄存器区别开来,后文对这种寄存器称之为数据寄存器,以示区分)。在机器模式(Machine Mode,本项目只支持该模式)下这些存储器主要包括以下六类:
- 处理器信息相关:例如处理器的厂商信息,架构信息,核心数等等,是一个芯片自身的I固有信息。
- 中断配置相关:例如中断开关以及中断入口等信息。
- 中断响应相关:例如中断原因,中断返回地址等信息。
- 存储器保护相关:设置不同地址空间的存储器的访问属性,例如可读可写可执行等等。
- 性能统计相关和调试接口相关
CSR的访问与当前指令,或者说程序处于何种模式密切相关,不同模式下所能访问的CSR数量都不同。如果强行访问一个本不应该在该模式下访问的CSR则会触发非法指令的异常。所以在设计CSR访问逻辑时,需要知道该CSR允许在哪(些)种模式下可以访问,而这需要仔细研读RISC-V SPEC相关的部分。除此之外,一条CSR指令并不会比一条ADD指令更复杂。同样可以套用前面总结的设计模板。
开始Coding
与先前所实现的指令类似,实现CSR
指令,需要以下几个EXU子模块的协同配合:
- exu_decode:指令解码模块,负责解析具体的访存指令。
- exu_regfile:寄存器文件模块,源操作数需要从此模块读出,读存储器的结果需要写回到此模块。
- exu_alu:指令执行模块,具体指访存地址的生成,以及其他控制信号。
- exu_wbck:结果写回模块,负责结果写回
基于上述划分标准,以下将详细介绍各个模块的设计细节。
指令译码
首先,我们需要从riscv-spec上找到CSR
指令所对应的编码格式,如下图所示:
官方risc-v spec
一共定义了6种CSR
指令,其中3个不需要立即数,而另外3个则需要。这些立即数只有5bit,且是0扩展的。所有的CSR
都需要将原值写回到数据寄存器。上述六种CSR
指令配合特殊的源操作数索引和目的操作数索引(等于0或者不等于0),就可以变化成众多的CSR
伪指令。从上图我们可以看出,对于CSR
指令:
- func7部分,即CODE[31:20],视为某个具体
CSR
的索引值,据此可确定当前CSR
到底要访问哪一个寄存器,这其中:- CODE[31:30],表征当前
CSR
寄存器是否可读写。 - CODE[29:28],表征当前
CSR
允许访问的最低用户权限(模式)。 - CODE[27:20],真正的
CSR
索引值。
- CODE[31:30],表征当前
- 可能需要使用源寄存器1,或者立即数。
- 一定会用到目的寄存器,但是其idx值未知。
- func3部分,即CODE[14:12],据此判定
CSR
指令的具体类型。 - opcode部分,即CODE[6:0],必须为1110011
在译码模块中,添加如下两行,解析具体的CSR
指令:
以及对应的rsen/rsidx/rdidx
,以rs1en
为例:
有3条CSR
指令需要用到立即数,这个立即数是个0扩展的,原值为5bit的数据。
算术运算
CSR
指令只是将特定的值更新到指定的CSR
寄存器中,除此之外不需要进行其他算术运算操作。因此,此处只需要生成特定的dff_ena
以及数据信号。由于本项目当前不涉及非法指令异常,因此默认不会有非法的CSR
访问操作。
//
// csr related part start.
wire csr_op = i_csrrw_op| i_csrrs_op | i_csrrc_op | i_csrrwi_op| i_csrrsi_op| i_csrrci_op;
// 当前csr指令是否包含写
wire csr_write_en = csr_op;
// 当前csr操作是否包含读
wire csr_read_en = csr_op;
// 生成写的数据
wire [31:0] csr_write_dat = ({32{i_csrrw_op }} & i_alu_rs1) | ({32{i_csrrs_op }} & i_alu_rs1)| ({32{i_csrrc_op }} & i_alu_rs1)| ({32{i_csrrwi_op}} & i_alu_imm)| ({32{i_csrrsi_op}} & i_alu_imm)| ({32{i_csrrci_op}} & i_alu_imm);
// 生成csr访问地址
wire [11:0] csridx = i_csridx;以下是mstatus实现部分
wire [31:0] mstatus;
wire [31:0] mstatus_nxt;
assign mstatus_nxt = csr_write_dat;
// mstatus的位域定义,来源于spec,此处做简化处理。
//assign mstatus_nxt[0] = 1'b0; //UIE
//assign mstatus_nxt[1] = 1'b0; //SIE
//assign mstatus_nxt[2] = 1'b0; //WPRI
//assign mstatus_nxt[3] = 1'b0; //MIE
//assign mstatus_nxt[4] = 1'b0; //UPIE
//assign mstatus_nxt[5] = 1'b0; //SPIE
//assign mstatus_nxt[6] = 1'b0; //WPRI
//assign mstatus_nxt[7] = 1'b0; //MPIE
//assign mstatus_nxt[8] = 1'b0; //SPP
//assign mstatus_nxt[10:9] = 2'b0; //WPRI
//assign mstatus_nxt[12:11] = 2'b0; //MPP
//assign mstatus_nxt[14:13] = 2'b0; //FS
//assign mstatus_nxt[16:15] = 2'b0; //XS
//assign mstatus_nxt[17] = 1'b0; //MPRV
//assign mstatus_nxt[18] = 1'b0; //SUM
//assign mstatus_nxt[19] = 1'b0; //MXR
//assign mstatus_nxt[20] = 1'b0; //TVM
//assign mstatus_nxt[21] = 1'b0; //TW
//assign mstatus_nxt[22] = 1'b0; //TSR
//assign mstatus_nxt[30:23] = 8'b0; //WPRI
//assign mstatus_nxt[31] = 1'b0; //SD// 根据索引值判定当前CSR指令是否是访问mstatus
wire csr_mstatus_sel = (csridx == 12'h300);
// 当前csr指令是否需要更新mstatus
wire mstatus_ena = csr_write_en & csr_mstatus_sel;
xf100_gnrl_dfflr #(32) mstatus_dfflr (clk, rst_n, mstatus_ena, mstatus_nxt, mstatus);
//将status的旧值读出来,备用(可能要写回)
wire [31:0] csr_read_dat = ({32{csr_mstatus_sel}} & mstatus);
如果CSR
指令需要写回,则写回的值需要送到写回接口上。
assign o_alu_wdat = i_lw_op ? o_alu_mem_din : csr_op ? csr_read_dat : alu_adder_res;
测试程序
我们从rv32ui-p-add.dump
中找到了所需要的测试程序,其反汇编代码如下所示:
红框中的代码,是根据源数据寄存器a0
中的值,更新MSTATUS
对应的位域。具体的,如果a0
中的第N位是1,则将MSTATUS
中对应的第N位设置为1. 此处的效果等价于将a0
的值写入MSTATUS
。
make run
仿真结果及分析
仿真环境不需要更新,直接在之前的基础上运行即可。会看到如下波形:
上图的解读如下:
- PC=0x80000168,识别到一个
CSR
指令,该指令需要使用源数据寄存器a0
,此时上一条指令已经将其更新为8。 - 该
CSR
指令需要更新MSTATUS
寄存器。 - 在下一周期,
MSTATUS
寄存器成功被更新为新值,表明功能达到预期。 - 由于目的数据寄存器的索引值是0,因此不需要写回。
rf_wen
为低。。
下一步,我们将探索仿真一个真实的应用程序,看看?
从零开始学RISC-V之CSR访问相关推荐
- linux apache设置web访问重定向_从零开始学Linux运维|30.Linux的目录结构
1.tree命令 linux下目录结构跟一个倒过来的树一样的,最顶层就是根目录 / tree这个命令就很形象 它够很方便的查看目录结构 使用"yum install tree -y" ...
- 6. 管理你的css和js文件 - 从零开始学Laravel
从零开始学laravel教程目录 在Laravel中我们可以直接将css和js文件放在app/public目录下,不过在正式项目开发中我们可能会使用Sass, Less, Stylus,Browser ...
- (21)Spring Boot过滤器、监听器【从零开始学Spring Boot】
2019独角兽企业重金招聘Python工程师标准>>> Spring Boot 系列博客] (0)前言[从零开始学Spring Boot] : http://412887952-qq ...
- RISC V (RV32+RV64) 架构 整体介绍
文章目录 riscv 市场 芯片介绍 软件介绍 开发板介绍 PC介绍 riscv 架构 编程模型(指令集/寄存器/ABI/SBI) 运行状态 指令集 寄存器 riscv32和riscv64两者的区别 ...
- 自学python3书籍-Python3.7从零开始学 PDF 全书影印版
给大家带来的一篇关于Python3.7相关的电子书资源,介绍了关于Python3.7.从零开始学.兄弟连方面的内容,本书是由清华大学出版社出版,格式为PDF,资源大小75.8 MB,刘宇宙/刘艳编写, ...
- 从零开始学Docker
从零开始学Docker 说明 Docker的安装 查看centos版本(Docker 要求CentOS系统的内核版本高于3.10) 升级软件包及内核 安装Docker 启动Docker 开机自动启动D ...
- 【云原生 | 从零开始学Docker】七丶实战提交自己的镜像以及docker网络
该篇文章已经被专栏<从零开始学docker>收录 实战以及网络 实战测试 制作自己的tomcat 1.准备镜像文件(tomcat的压缩包,jdk的压缩包) 2.编写dockerfile文件 ...
- 从零开始学爬虫系列3:漫画下载,动态加载、反爬虫这都不叫事!
1 前言 前文回顾: 从零开始学爬虫系列1:初识网络爬虫之夜探老王家 从零开始学爬虫系列2:下载小说的正确姿势 经过上两篇文章的学习,爬虫三步走:发起请求.解析数据.保存数据,已经掌握,算入门爬虫了吗 ...
- JAVE EE 企业级开发之从零开始学JAVA【51CTO技术论坛】
http://bbs.51cto.com JAVE EE 企业级开发之从零开始学JAVA 从零开始学JAVA?YES!本刊内容全部为午饭redking整理.撰写,所涉及内容均为原创,非 ...
- 从零开始学 Python 之运算符
从零开始学 Python 之运算符 前言 大家好,这里是「痴海」从零开始学习 Python 系列教程.此文首发于「痴海」公众号,欢迎大家去关注.学习一门语言最好的办法,就是教懂别人.在这公众号,我会从 ...
最新文章
- python软件在下载库文件_python – 并行下载多个文件的库或工具
- 英特尔核芯显卡控制面板没有了_【有趣】第41期:被英特尔取消发售的CPU长啥样?...
- 从数据的角度解析计算机的发展,2017计算机知识考前冲刺试题及答案
- 在控制台中实现“单词竞猜”游戏 C# 猜词游戏
- DreamFactory 第8章 保护您的DreamFactory环境
- 用CONVERT命令转换FAT到NTFS,合适吗?
- java里新建线程设置线程名字_多线程开发不得不掌握,设置和获取线程名称及JVM如何运行的...
- SAP soamanager发布的Webservice服务,调用时出现http500报错
- Filter Concatenationd的理解
- 程序员的自我修养 -- 读书笔记
- οnchange相当于前端js函数,可以实现前端实时更新以及修改验证
- 网上图片的几种保存方法
- 2014-2015-2 《Java程序设计》课程学生博客列表
- python学习笔记(汇总)
- Unity 3D光源-Directional平行光/逆光效果,光晕详解、教程
- 通往财富自由之路详细笔记(16)
- R语言绘制heatmap热图
- 深圳高新技术企业补贴政策
- MySQL数据库实操教程(18)——数据库事务及其隔离级别
- UDT:基于UDP的可靠传输协议