zoukankan      html  css  js  c++  java
  • 【原创】MIPS中断系统的板级验证及实例测试

    五一”假期前后这约五天时间,终于将MIPS中断系统进行了板级验证及实例测试。因为老师给的交叉编译工具不会用,所以测试代码完全用MIPS汇编编写。使用MARS而没有用QtSpim,其实我觉得SPIM这个东西比较复杂,但是确实很好用,但是MARS是开源,可以根据你的需求修改这个汇编器(这个汇编器功能很强大,笔者至今没有用熟练)。据传说MARS可以支持link异常处理程序,但是我没有这么做,手动链接也是一样的,本来我们做的就是最底层的事情。
    首先,必须要强调的是MIPS中断有别于Intel中断,两者用本质上的区别。Intel中断使用中断控制器8259控制中断,但是MIPS体系架构不同,它仅仅使用了很简单巧妙的方式处理中断。据我个人浅薄认识,8259是用来扩展中断源,而并不能认为只有8259可以控制中断,它控制的更多的是优先级。其实对中断响应等更具备控制权限的是CPU,所有的外部信号都需要由处理器控制是否响应等等。笔者,已经模仿8259的功能写了一个片上中断控制器,而今天所讲的中断系统并不包含8259,仅仅是捕获最原始的中断源,即将中断源的输出信号直接与Cause(IP)位的某一位相连。
    为什么讲这么多有关8259的事情,因为这里有一个误区,也是我们做中断做了N多久遗留的误区。就是我们认为中断请求信号仅仅是一个脉冲,这个脉冲可能持续一个时钟周期,也可能持续N个时钟周期,然而这种想法一定是错的。《Intel微处理器》P356页有一个标准的INTR输入和INTA输出的时序图。所有INTR信号都是一个从低电平越变到高电平的信号,并持续保持高电平。另外,《微机原理与接口技术》这本书中P273页详细描述了8253的方式0的功能:中断信号发生器。如下图所示。当计数到0后,将产生一个持续的高电平。
    我想说的是,用FPGA去验证和我们实际学到的知识理论可能会有很大的不同。就拿我现在最不理解的来说,《Intel微处理器》P357页描述使INTR输入为边沿触发信号,其处理办法就是将中断请求信号作为D触发器的CLK,如下图所示。
    这种方式在FPGA中绝对是没法实现的,因为所有人都知道做SOC最重要的就是时钟。时钟是所有时序电路的灵魂,用一个中断请求信号作为CLK,非常不稳定,我甚至怀疑是否允许这样做。其实,还有更多的例子。我觉得不能讲书中的电路图或者设计方式生搬硬套到FPGA设计中,而是要自己进行设计和转换。还有,Intel的东西只是一种参考、一种理论,并不是绝对的,并不是一成不变的。
    说了那么多有关Intel的东西,只是想做个比较。与之对照的自然是MIPS。MIPS采用很简单的方式处理中断。其实,说简单点而就是仅使用CP0的部分处理器实现,很多工作都由软件来进行。同时,N多MIPS手册或者《see mips run》都强调MIPS更乐于使用Compability方式而非Intel的向量化方式。首先,我觉得采用向量化的方式最大的好处就是快速,快速地定位到产生向量的中断处理程序中。须知Intel可以处理256个中断。而此中断包含了异常(如溢出)。而MIPS仅有不多的异常,此异常包含中断。这个概念最开始让我们很是琢磨不清,一会儿异常包含中断,一会儿中断包含异常。但是仔细想想,无论哪种方式都只是非正常执行外的一种处理方式。道理很类似,非常类似。所有的中断都只对系统不会产生负面影响的内部或外部的要求系统处理的信号,系统可以不理睬。而一场则是负面影响,系统若不长时间处理会产生极大的危害。
    所谓Compatibility中断模式,其实我个人认为也是由于在MIPS中,一场包含中断,系统只提供8个中断源接口(2个软件、6个硬件)。不要认为,接口少。可以讲中断控制器的INTR信号直连如其信号源,很多MIPS处理器都是这样。由于我们只是做一个有关学习的SOC,所以直接将硬件中断源与之相连。因此,很多按键灯外设需要认为地将INTP信号持续拉高。
    处理流程可以完全按照MIPS手册的General Exception Handler来处理。这里唯一需要注意的是,异常也是有优先级的。这个优先级可以使用全译码的方式控制,也可以使用诸如硬件排队器、菊花链的方式控制。而Cause(ExcCode)位是保持最近的一次产生异常的编码。一定是最近的一次,比如,在一条ADD指令的Fetch阶段产生了一个外部中断,而当执行后发现产生了OverFlow,那么Cause(ExcCode)位也必须按照优先级的不同修改,尽管中断是先发生的。当然这也解释了中断优先级最低的原因,中断pending信号是一直保持的,就算我的处理器不响应也不会对处理器产生危害,但是溢出等其它异常就可以,因此中断具有最低优先级。
    其实,做中断与CP0这块仿真时,我建议大家不要怕搓,大胆尝试,大胆地去设计和验证。当你发现你的设计不稳定或者有bug时就证明你的设计一定有问题,就需要修改。这部分的仿真我大概前前后后陆陆续续做了近两个月,虽不是一直在做,但是确实在一直在思考。我看到很多书,或者很多硕士论文,或者很多pudn的代码。这个部分的东西都做的很烂。这个部分最重要的不是完全和MIPS的一模一样,而是可以用,可以响应中断,我觉得就可以了。有的学校的MIPS处理器声称可以6级中断嵌套,我觉得这是完全没必要的。中断嵌套只是保护处理器、保护堆栈区的一种方式,只要有稳定的中断处理程序谁都可以中断嵌套。因此,只要攻破了一级中断,你也就一定可以攻破多级中断。因为非向量化式的中断完全由INT-entry程序判断中断优先级。向量化的中断我也实现过,那个优先级是由译码或者排队器做的。可以说嵌套靠的不是控制单元,而是优先级。所以最重要的是单级中断。一定要做出一个可以板级验证的单级中断,再去思考多级中断。笔者就犯了冒进的例子。血的教训。
    处理中断还有一个难点就是理解原子性,这个概念其实是在OS课中才接触到的。我也是因为不明白为什么一定要原子,去看了AST的《现代操作系统》。有疑问的推荐那本书。
    就中断系统而言,会发生原子操作的地方在于即将处理异常的时候,需要同时利用时钟上升沿做三件事情:1)将EXL置位;2)将PC保存入EPC;3)修改Cause(ExcCode)。另外,当异常处理程序结束时,也要进行原子操作:1)将EPC的值返回给PC;2)清楚EXL位。
    这就是一个经典的生产者——消费者模型。很多指令解决了这一问题,比如set and lock(IBM的好型),XCHG指令等等。这是MIPS体系结构中一个很经典的设计,完全由简单的控制信号控制同时写入,简单迅速。
    剩下的所有内容其实都是靠软件来实现,硬件就做这么些事情。笔者的中断系统是靠秒闪灯验证,这也是老师给的验证方式(真心简单方便还好)。主程序和中断程序共同维护一段儿内存,该内存变量为second。使用TC0(FPGA实现的8253)方式0每隔1S产生一个中断信号,进入中断处理程序。在中断处理程序中,将second增加1写入内存。主程序初始化TC0,随后进入死循环,不断读入second值,与pre second比较,若相等则继续循环,若不等,则将当前second值写入LED地址,继续循环。

    其实,说起来很简单,但是实现起来走的弯路会很多。很多人做了这东西,认为自己可以正常处理了或者可行了,我觉得都是很不负责任的。这东西是必须由特定的程序来验证的,而并不是指令集,只要一条指令就可以验证了。还有一点,我觉得很重要。就是搞FPGA设计不要完全参照别人的,有些网上的代码或者什么的都是很取巧的,比如我印象最深的读取RAM地址中的值时,诸多的程序都写成assign rd <= RAM[addr];试问,如果一个RAM可以用assign语句来如此迅速的读取内容,那么我们为什么还要GPR了呢?地址一边,RAM_rd立刻就改变,这是组合电路,并不是存储器读的真正时序。我觉得搞FPGA,不能用语言的技巧使你的仿真可以正确,而是要先设计,所有的程序必须完全按照你自己的设计来,这样就够了。你的设计可以不好,但是这种东西,一定可以实现,一定可以拿到板子上跑。

  • 相关阅读:
    修改mysql的时间/时区
    vue 3.0一些理解
    关于css中常用几种选择器的整理
    docker中MySQL8.0登录提示caching_sha2_password问题解决方法
    java请求url返回json
    weblogic11G 修改密码
    每天一个小知识
    出一套柠檬班测试开发视频(百度网盘)
    JAVA自动化,使用UIAutomator定位
    JAVA自动化,解决Appium无法输入中文问题
  • 原文地址:https://www.cnblogs.com/bombe1013/p/3294677.html
Copyright © 2011-2022 走看看