CPU设计实战—异常处理指令

异常类型以及精确异常的处理

异常有点像中断,处理完还要回到原来的状态,所以需要对之前的状态进行保存。本CPU主要实现对以下异常的处理:

1.外部硬件中断

2.复位异常

3.系统调用异常(发生在译码阶段)

4.溢出异常(发生在执行阶段)

5.自陷指令异常(发生在执行阶段因为需要进行条件判断)

6.无效指令异常(发生在译码阶段)

为了不破坏原程序的执行,异常指令之前的指令都要确保执行完成,而异常指令和其之后的指令需要取消。这要求异常发生的循序和指令发生的顺序相同。可会有例外吗?

由于流水线的特性,不同指令的异常可能发生在不同阶段。例如:加载指令在访存阶段发生未对齐异常,而下一个指令是无效指令在译码阶段发生异常。无效指令先发生异常,顺序错误。如何解决?

先发生的异常不立即处理,先进行标记,所有的异常统一留到访存阶段进行处理

一、异常处理过程

 异常发生之后进行的处理:

如果发生,先看当前是否处于异常处理阶段(根据状态寄存器的EXL字段);

如果正在异常处理,接着判断是否处于中断阶段,是的话则不处理此中断(异常处理过程会禁止中断);

不是处于中断异常则保存异常原因,进入异常处理例程即可。

如果没有正在进行异常处理:

1.先保存异常原因(Cause寄存器的Execode字段)

2.将保存异常返回地址到EPC(这时候需要判断是否为延迟槽指令?PC-4,BD=1:PC,BD=0)

4.转移到异常处理例程(最后就是根据异常类型确定PC的值是哪一个入口地址)

 EXL表示当前是否在异常状态EPC保存异常返回地址BD是当发生异常的指令在分支延迟槽时被置位

 如果异常指令是延迟槽指令,那么也必须执行上一条转移指令(PC-4)

二、实现思路

我们先在译码(系统调用,无效,异常返回)执行阶段(自陷,溢出)判断是否有相关异常发生并传递给访存阶段对不同异常结合CP0寄存器进行具体判断。如果需要处理,就转移到异常处理入口地址(在异常向量表中有定义),同时需要清除回写阶段前的所有寄存器

自陷异常

通过条件判断是否发生异常,如果发生就进入异常处理例程

 系统调用异常

当我们想要切换工作模式(比如获得更高权限进入内核模式),通过调用系统异常指令来实现修改工作模式状态位:即CP0中Status的UM字段。但是本CPU没有实现其他模式。

系统异常返回

作用是返回异常出现之前的指令,异常结束,具体操作为:

1.EPC寄存器(存储异常指令地址)的值给到PC

2.清除异常状态(EXL字段清零)

三 具体实现思路

1.在各个阶段(译码阶段需要判断延迟槽)收集异常状态将信号(异常判断信号与异常地址)传送到访存阶段

2.访存阶段判断异常是否处理(需要根据CP0中的一些寄存器):

需要处理:进入异常地址(如果是异常返回指令则进入EPC的地址);清除之前阶段;修改CP0(进入异常状态等)

四 各个阶段具体实现

1.PC阶段

如果异常到来就使用新的PC值

	  end else if(stall[1] == `NoStop) beginid_pc <= if_pc;id_inst <= if_inst;

2.各个寄存器阶段

如果异常来临把所有输出信号赋初始值

		end else if(flush == 1'b1 ) beginex_aluop <= `EXE_NOP_OP;ex_alusel <= `EXE_RES_NOP;ex_reg1 <= `ZeroWord;ex_reg2 <= `ZeroWord;ex_wd <= `NOPRegAddr;ex_wreg <= `WriteDisable;ex_excepttype <= `ZeroWord;ex_link_address <= `ZeroWord;ex_inst <= `ZeroWord;ex_is_in_delayslot <= `NotInDelaySlot;ex_current_inst_address <= `ZeroWord;	is_in_delayslot_o <= `NotInDelaySlot;	

3.译码阶段

对指令进行译码,如果是异常指令保存状态:如系统调用异常返回,自陷指令在执行阶段还要进行条件判断所以这里不记录

然后把异常状态都保存到一个信号中

//exceptiontype的低8bit留给外部中断,第9bit表示是否是syscall指令//第10bit表示是否是无效指令,第11bit表示是否是trap指令assign excepttype_o = {19'b0,excepttype_is_eret,2'b0,instvalid, excepttype_is_syscall,8'b0};

4.执行阶段

判断执行阶段里的异常状态:如溢出自陷指令条件判断并把相关信号输出:

assign excepttype_o = {excepttype_i[31:12],ovassert,trapassert,excepttype_i[9:8],8'h00};

5.访存阶段

主要目的是进一步判断是否要发生异常类型(结合CP0中的信号判断)以及具体哪个异常

什么时候发生异常:复位,异常和暂停情况不处理异常,所以取指地址不为0才发生异常

区分是哪个异常类型(不能只根据传过来的异常类型,因为有些还需要CP0中的额外条件):

中断异常:当处于中断或者异常情况下不处理中断

发生中断的依据是: Cause 寄存器的IP字段不为0,且Status寄存器中相应的中断掩码字段IM也不为0,另外,Status 寄存器的EXL字段为0,表示不处于异常处理过程中,Status 寄存器的IE字段为1,表示中断使能。

其他异常类型没有额外条件,只要之前异常触发了就可以。

			if(current_inst_address_i != `ZeroWord) beginif(((cp0_cause[15:8] & (cp0_status[15:8])) != 8'h00) && 
(cp0_status[1] == 1'b0) && (cp0_status[0] == 1'b1)) beginexcepttype_o <= 32'h00000001;        //interruptend else if(excepttype_i[8] == 1'b1) beginexcepttype_o <= 32'h00000008;        //syscallend else if(excepttype_i[9] == 1'b1) beginexcepttype_o <= 32'h0000000a;        //inst_invalidend else if(excepttype_i[10] ==1'b1) beginexcepttype_o <= 32'h0000000d;        //trapend else if(excepttype_i[11] == 1'b1) begin  //ovexcepttype_o <= 32'h0000000c;end else if(excepttype_i[12] == 1'b1) begin  //返回指令excepttype_o <= 32'h0000000e;endend

 具体每个异常类型对应的输出回顾译码和执行阶段做的定义:

 到这一步才算完成对异常类型的判断!!!

下面是根据不同的异常类型做不同的操作,主要是给修改PC以及寄存器

6.根据不同的异常类型修改CP0的值(主要记载返回地址和返回原因)

CP0中重要寄存器作用:

1.EPC是异常程序计数器(Exception Program Counter),用来存储异常返回地址,一般情况下,存储发生异常的指令的地址,但是,如果发生异常的指令位于延迟槽中,那么EPC存储的是前一条转移指令的地址。该寄存器可读、可写。

2.cause寄存器的BD字段
当发生异常的指令处于分支延迟槽(Branch DelaySlot)时,该字段被置为1。ExeCode是表示异常原因

3.Status寄存器的EXL字段

表示是否处于异常级( Exception Level), 当异常发生时,会设置本字段为1,表示处理器处于异常级,此时,处理器会进入内核模式下工作,并且禁止中断。

中断指令:

依据发生异常的指令是否位于延迟槽中,保存返回地址设置EPC寄存器的值,以及Status 寄存器的BD字段,如果位于延迟槽中,那么设置EPC寄存器为上一条指令的地址,Status 寄存器的BD字段为1,反之,设置EPC寄存器为发生异常指令的地址,Status寄存器的BD字段为0。另外,设置异常状态设置Status 寄存器的EXL字段为I,表示处于异常级,中断禁止。最后,保存返回原因设置Cause寄存器的ExcCode字段5'b00000,表示异常原因是中断。

系统调用异常:

分两种情况。
(1)如果Status寄存器的EXL字段为0,那么依据发生异常的指令是否位于延迟槽中,设置EPC寄存器的值,以及Status寄存器的BD字段。如果位于延迟槽中,那么设置EPC寄存器为上一条指令的地址,Status 寄存器的BD字段为1,反之,设置EPC寄存器为发生异常指令的地址,Status 寄存器的BD字段为0。然后,设置Status寄存器的EXL字段为1,表示处于异常级,中断禁止。最后,设置Cause寄存器的ExcCode字段为5"b01000,表示异常原因是系统调用指令syscall,参考第10章的表10-7。
(2)如果Status寄存器的EXL字段为1,表示当前已经处于异常级了,又发生了新的异常,那么只需要将异常原因保存到Cause寄存器的ExcCode字段,此处设置为5'b01000,表示异常原因是系统调用指令syscall。

3.无效指令异常
与系统调用异常的处理过程类似,只是设置Status寄存器的ExcCode字段为5"b01010,表示异常原因是无效指令。
4.自陷异常
与系统调用异常的处理过程类似,只是设置Status寄存器的ExcCode字段为5'b01101,表示异常原因是自陷. 
5.溢出异常
与系统调用异常的处理过程类似,只是设置Status寄存器的ExcCode字段为5'b01100,表示异常原因是溢出。
6.异常返回指令eret
清除Status寄存器的IE字段,表示中断允许。

6.控制模块

根据异常类型给出下一个PC应有的值,这个值根据异常处理入口例程;

如果是异常返回地址,则跳转到异常返回地址

	always @ (*) beginif(rst == `RstEnable) beginstall <= 6'b000000;flush <= 1'b0;new_pc <= `ZeroWord;end else if(excepttype_i != `ZeroWord) beginflush <= 1'b1;stall <= 6'b000000;case (excepttype_i)32'h00000001:		begin   //interruptnew_pc <= 32'h00000020;end32'h00000008:		begin   //syscallnew_pc <= 32'h00000040;end32'h0000000a:		begin   //inst_invalidnew_pc <= 32'h00000040;end32'h0000000d:		begin   //trapnew_pc <= 32'h00000040;end32'h0000000c:		begin   //ovnew_pc <= 32'h00000040;end32'h0000000e:		begin   //eretnew_pc <= cp0_epc_i;enddefault	: beginendendcase 						end else if(stallreq_from_ex == `Stop) beginstall <= 6'b001111;flush <= 1'b0;		end else if(stallreq_from_id == `Stop) beginstall <= 6'b000111;	flush <= 1'b0;		end else beginstall <= 6'b000000;flush <= 1'b0;new_pc <= `ZeroWord;		end    //ifend      //always

7.定时中断的结构实现

将时钟中断输出作为一个中断信号输入,这样就可以处理时钟中断了,从而验证异常相关指令是否实现正确。
 

8、测试程序

系统调用异常测试程序

 当指令根据系统调用异常的指示入口地址跳转到这里后,需要自己写代码去进行在EPC内进行PC+4的操作,不然等异常返回指令后PC按照EPC内的值跳转后还是在系统调用指令处继续异常。

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

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

相关文章

Linux下磁盘分区类型及文件系统扩容

本篇文章基础知识点较多&#xff0c;文章偏长。建议收藏~ 之前介绍过一篇文章 重新构建KVM虚拟机基础镜像&#xff0c;当中有个待优化的点。 Centos 官方的镜像中默认的系统盘(/dev/vda)的大小是8G空间 但是实际使用时&#xff0c;8G的系统盘肯定不满足需求。这个时候我们就需…

做好外贸网站SEO优化,拓展海外市场

随着全球贸易的发展和互联网的普及&#xff0c;越来越多的外贸企业将目光投向了网络&#xff0c;希望通过建立网站来拓展海外市场。然而&#xff0c;在竞争激烈的外贸市场中&#xff0c;要让自己的网站脱颖而出&#xff0c;吸引更多的目标客户&#xff0c;就需要进行有效的SEO优…

openGauss学习笔记-246 openGauss性能调优-SQL调优-经验总结:SQL语句改写规则

文章目录 openGauss学习笔记-246 openGauss性能调优-SQL调优-经验总结&#xff1a;SQL语句改写规则246.1 使用union all代替union246.2 join列增加非空过滤条件246.3 not in转not exists246.4 选择hashagg246.5 尝试将函数替换为case语句246.6 避免对索引使用函数或表达式运算2…

PyTorch学习笔记之基础函数篇(十三)

文章目录 7.7 torch.ceil() 函数7.8 torch.floor() 函数7.9 torch.clamp() 函数7.10 torch.neg() 函数7.11 torch.reciprocal() 函数7.12 torch.rsqrt() 函数7.13 torch.sqrt() 函数 7.7 torch.ceil() 函数 在PyTorch中&#xff0c;torch.ceil 函数用于对张量&#xff08;tens…

面试算法-50-二叉树的最大深度

题目 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;3 解 class Solution {public int maxDepth(TreeNo…

《算法设计与分析第二版》100行 C语言实现 广度度优先算法 BFS——最短距离

抄录自课本P157页。 #include <stdio.h> #define MAXQ 100 // 队列大小 #define MAxN 10 // 最大迷宫大小 int n8; // 迷宫大小 char Maze [MAxN][MAxN] {{O,X,X,X,X,X,X,X,},{O,O,O,X,O,X,O,X,},{X,X,O,O,O,X,O,X,},{X,X,O,X,O,X,X,X,},…

Git ignore: 忽略与清除

一、vs、vc #.svn .clang-format .gitignore Src/[Dd]ebug/ Src/[Rr]elease/ .vs .vs/* ​ # other file *.txt *.log *LOG/ *log/ ​ # Compiled Object files *.slo *.lo #*.o *.obj ​ # Precompiled Headers *.gch *.pch ​ # Compiled Dynamic libraries #*.so *.dylib #…

LightDB24.1 Sequence支持设置minvalue小于INT64_MIN

背景介绍 Oracle数据库支持设置sequence的minvalue为-1000000000000000000000000000&#xff0c;在用户迁移到LightDB时&#xff0c;sequence设置minvalue为-1000000000000000000000000000会报错。为了兼容Oracle数据库的使用习惯&#xff0c;在LightDB24.1版本中&#xff0c;…

HDFS概述及常用shell操作

HDFS 一、HDFS概述1.1 HDFS适用场景1.2 HDFS优缺点1.3 HDFS文件块大小 二、HDFS的shell操作2.1 上传2.2 下载2.3 HDFS直接操作 一、HDFS概述 1.1 HDFS适用场景 因为HDFS里所有的文件都是维护在磁盘里的 在磁盘中对文件的历史内容进行修改 效率极其低(但是追加可以) 1.2 HDF…

Linux电源管理——系统Suspend/Resume流程

本篇文章主要是自己的学习笔记&#xff0c;主要内容是分析linux系统中设备的Suspend和Resume流程&#xff0c;用到的内核版本为 linux-4.14。 目录 1、Linux 内核的Suspend方法 2、__device_suspend 函数 3、pm_op 函数 4、suspend_enter 函数 5、resume流程 1、Linux 内…

dockerfile更改docker镜像源

方法一&#xff1a; ## 更换源 RUN sed -i s/deb.debian.org//mirrors.aliyun.com/g /etc/apt/sources.list \ && apt-get update 方法二&#xff1a; RUN echo "deb http://mirrors.tuna.tsinghua.edu.cn/debian/ buster main contrib non-free" >/…

js中副作用的消除还解决了并行计算带来的竞争问题,具体是如何解决的

在JavaScript中&#xff0c;副作用是指对外部环境产生的可观察的变化&#xff0c;例如修改全局变量、修改DOM元素等。副作用的存在可能导致代码的可维护性和可测试性下降&#xff0c;并且在并行计算中可能引发竞争问题。 不纯的函数有可能访问同一块资源&#xff0c;如果先后调…

走近 AI Infra 架构师:在高速飞驰的大模型“赛车”上“换轮子”的人

如果把大模型训练比作 F1 比赛&#xff0c;长凡所在的团队就是造车的人&#xff0c;也是在比赛现场给赛车换轮子的人。1% 的训练提速&#xff0c;或者几秒之差的故障恢复时间&#xff0c;累积起来&#xff0c;都能影响到几百万的成本。长凡说&#xff1a;“大模型起来的时候&am…

算法详解——选择排序和冒泡排序

一、选择排序 选择排序算法的执行过程是这样的&#xff1a;首先&#xff0c;算法遍历整个列表以确定最小的元素&#xff0c;接着&#xff0c;这个最小的元素被置换到列表的开头&#xff0c;确保它被放置在其应有的有序位置上。接下来&#xff0c;从列表的第二个元素开始&#x…

事件高级、

文章目录 1.注册事件&#xff08;绑定事件&#xff09;addEventListener 事件监听方式attachEvent 事件监听方式、兼容性解决方案 * 2.删除事件&#xff08;解绑事件&#xff09;删除事件的方式删除事件兼容性解决方案 * 3.DOM事件流4.事件对象使用语法兼容性方案*常见属性和方…

边缘计算+WEB端应用融合:AI行为识别智能监控系统搭建指南 -- 边缘设备图像识别及部署(二)

专栏目录 边缘计算WEB端应用融合&#xff1a;AI行为识别智能监控系统搭建指南 – 整体介绍&#xff08;一&#xff09; 边缘计算WEB端应用融合&#xff1a;AI行为识别智能监控系统搭建指南 -- 边缘图像识别及部署&#xff08;二&#xff09; 前言边缘图像识别与推流整体思路原始…

Allegro许可类型

随着科技的飞速发展&#xff0c;数字化转型已成为企业提升竞争力的必经之路。在这个过程中&#xff0c;软件许可作为企业合规运营的关键环节&#xff0c;发挥着至关重要的作用。Allegro作为业界领先的软件解决方案提供商&#xff0c;提供了一系列丰富多样的许可类型&#xff0c…

vue+elementUI实现右击指定表格列的单元格显示选择框

一、template代码如下&#xff1a; 1、表格单元格中添加的代码&#xff1a; <div v-if"item.label 铁心级号" contextmenu.prevent"openRightMenu($event, item, scope.$index)" style"height: 38px; line-height: 38px;"><span styl…

海康威视添加新摄像头到原建的网络监控平台中

一、适用场景 1、企业已经存在一套海康威视的监控网络系统&#xff1b; 2、根据业务的需求&#xff0c;要新增加一些摄像头&#xff1b; 3、原施工方忙碌&#xff0c;为新增加的摄像头施工成本较高&#xff1b; 4、新增加海康威视的摄像头视频监控&#xff0c;保存在原建的监控…

构建强大的API:Django中的REST框架探究与实践【第146篇—Django】

&#x1f47d;发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 构建强大的API&#xff1a;Django中的REST框架探究与实践 在当今的Web开发中&#xff0c;构…