自己动手写了第三阶段的处理器——教学OpenMIPS处理器蓝图

我们会继续上传新书《自己动手写处理器》(未公布)。今天是第十条。我每星期试试4


      从本章開始将一步一步地实现教学版OpenMIPS处理器。本章给出了教学版OpenMIPS的系统蓝图,首先介绍了系统的设计目标,当中具体说明了OpenMIPS处理器计划实现的5级流水线。

3.2节给出了OpenMIPS处理器的接口示意图,及各个接口的作用。

3.3节简单解释了各个源码文件的作用。最后描写叙述了OpenMIPS处理器的实现方法,读者将发现本书给出的实现方法与现有书籍的方法全然不同,更加易于理解、便于实践。

3.1 系统设计目标

3.1.1 设计目标

      本书第二部分设计实现的教学版OpenMIPS处理器,是一款具有哈佛结构的32位标量处理器,兼容MIPS32 Release 1指令集架构(后文不再注明Release 1)。这种优点是能够使用现有的MIPS编译环境,如:GCC编译器等。OpenMIPS的设计目标例如以下。

  •  五级整数流水线,各自是:取指、译码、运行、訪存、回写
  •  哈佛结构。分开的指令、数据接口
  •  32个32位整数寄存器
  •  大端模式
  •  向量化异常处理。支持精确异常处理
  •  支持6个外部中断
  •  具有32bit数据、地址总线宽度
  •  能实现单周期乘法
  •  支持延迟转移
  •  兼容MIPS32指令集架构。支持MIPS32指令集中的全部整数指令
  •  大多数指令能够在一个时钟周期内完毕

      上述设计目标都非常easy理解,除了延迟转移和精确异常,前者将在第8章“转移指令的实现”中介绍,后者将在第11章“异常相关指令的实现”中介绍。

3.1.2 五级整数流水线

      本书讲的是计算机中的流水线,首先听一听维基百科中对计算机流水线的定义:流水线是指将计算机指令处理过程拆分为多个步骤,并通过多个硬件处理单元并行运行来加快指令运行速度。此处有两个关键词:(1)拆分;(2)并行。指令的处理从直观上分析至少能够拆分为三步:从存储器取出指令、解释指令、依照解释的结果运行,简单的说就是:取指、译码、运行。

假设我们仅仅有一个硬件处理单元,这个单元既要取指,又要译码,还要运行。假设上述三种操作都能够在时间T完毕,那么一条指令的处理时间为3T,n条指令的处理时间就为3nT。可是假设我们设计有三个硬件单元。分别做这三项工作的一项。那么就能够在运行的同一时候对下一条指令译码。在对下一条指令译码的同一时候还能够再取一条指令。这就是经典的三级流水线,如图3-1所看到的。


      从图3-1可知,在三级流水线上运行3条指令所需时间为5T,而如果没有使用流水线则须要9T,流水线确实加快了指令运行。ARM7採用的就是三级流水线。但世间事没有这么简单完美的,上面如果取指、译码、运行须要的时间都是T。实际并不是如此。比方取指的时间就可能非常长,如果取指须要2T时间,那么如图3-2所看到的。


      可见在3T-4T的时间段、5T-6T的时间段,流水线在等待取指结束,此时译码阶段、运行阶段都停滞,这样一来自然就慢下来。最后,运行3条指令所需时间为8T。

解决取指时间过长的措施是引入缓存(Cache),处理器从缓存读取指令仅仅须要1个时钟周期。

      另一种情况是运行阶段时间过长,比方指令为载入/存储指令(Load/Store)时,因为涉及到訪问存储器,运行阶段所需的时间就可能大于T,此时也会导致流水线停滞。为了解决这样的情况下的流水线停滞问题,引入了五级流水线,各自是:取指、译码、运行、訪存、回写。如图3-3所看到的。


      当中訪存阶段(Memory Access)的作用是从存储器装载数据到寄存器或者将寄存器数据保存到存储器。当然,假设不是Load/Store指令则不须要这一步,此时在訪存阶段就仅仅是将运行阶段的运算结果送到下一级回写阶段。回写阶段(Write Back)的作用是将数据写入目的寄存器。

ARM9就採用了这样的五级流水线。OpenMIPS的设计目标也是五级流水线。

详细而言,OpenMIPS五级流水线各个阶段的主要工作例如以下。

  •  取指阶段:从指令存储器读出指令。同一时候确定下一条指令地址。

  •  译码阶段:对指令进行译码。从通用寄存器中读出要使用的寄存器的值,假设指令中含有马上数,那么还要将马上数进行符号扩展或无符号扩展。假设是转移指令。而且满足转移条件,那么给出转移目标,作为新的指令地址。
  •  运行阶段:依照译码阶段给出的操作数、运算类型,进行运算,给出运算结果。假设是Load/Store指令。那么还会计算Load/Store的目标地址。
  •  訪存阶段:假设是Load/Store指令,那么在此阶段会訪问数据存储器,反之,仅仅是将运行阶段的结果向下传递到回写阶段。同一时候,在此阶段还要推断是否有异常须要处理,假设有,那么会清除流水线,然后转移到异常处理例程入口地址处继续运行。

  •  回写阶段:将运算结果保存到目标寄存器。

      读者可能对上述流水线各个阶段的主要工作还不全然理解,没有关系,本书也不是一次实现上述所有工作,而是逐步完好。一開始。仅仅实现流水线各个阶段的基本工作,慢慢地丰富、完好。

3.1.3 指令运行周期

      OpenMIPS设计目标中提到:实现MIPS32指令集中的全部整数指令。而且大多数指令能够在一个时钟周期内运行完毕。

详细而言。OpenMIPS实现的全部指令运行完毕须要的时钟周期如表3-1所看到的。


      对表3-1有下面几点说明。

      (1)OpenMIPS计划採用试商法完毕除法运算,对于32位的除法,运行阶段至少须要32个时钟周期,再加上一些准备工作须要的时钟周期,最后须要36个时钟周期才干运行完毕。在第7章“算术操作指令的实现”中会详细介绍除法指令的实现过程。

      (2)乘累加指令madd、maddu。乘累减指令msub、msubu都须要2个时钟周期才干运行完毕。主要是由于这4条指令都要做两次运算。一次乘法、一次加/减法,假设将这两次运算放在运行阶段的一个时钟周期中完毕,那么会使运行阶段所须要的时间明显添加。从而减少OpenMIPS工作时钟的频率,因此。OpenMIPS设计在运行阶段使用两个时钟周期完毕这4条指令,一个时钟周期进行乘法。下一个时钟周期进行加/减法。在第7章“算术操作指令的实现”中会详细介绍乘累加、乘累减指令的实现过程。

3.2 教学版OpenMIPS处理器接口

      教学版OpenMIPS处理器的外部接口如图3-4所看到的。

採用左边是输入接口,右边是输出接口的方式绘制。这样比較直观,便于理解。各接口的描写叙述如表3-2所看到的,能够分为三类:系统控制接口(包含复位、时钟、中断)、指令存储器接口、数据存储器接口。



3.3 文件说明

      OpenMIPS是五级流水线处理器。流水线各个阶段的模块、相应的文件如图3-5所看到的。图中每一个模块的上方标注的是模块名,下方标注的是相应的文件名称。模块之间的关系没有绘出,由于关系比較复杂,在书中不便绘制,读者能够參考本书光盘中的“openmips模块连接关系图.vsd”文件。当中绘制了模块之间具体的连接关系。


      详细说明例如以下。

      (1)取指阶段

  •  PC模块:给出指令地址,当中实现指令指针寄存器PC。该寄存器的值就是指令地址。相应pc_reg.v文件
  •  IF/ID模块:实现取指与译码阶段之间的寄存器,将取指阶段的结果(取得的指令、指令地址等信息)在下一个时钟传递到译码阶段。

    相应if_id.v文件

      (2)译码阶段

  •  ID模块:对指令进行译码,译码结果包含运算类型、运算所需的源操作数、要写入的目的寄存器地址等。相应id.v文件。
  •  Regfile模块:实现了32个32位通用整数寄存器,能够同一时候进行两个寄存器的读操作和一个寄存器的写操作。

    相应regfile.v文件。

  •  ID/EX模块:实现译码与运行阶段之间的寄存器。将译码阶段的结果在下一个时钟周期传递到运行阶段。相应id_ex.v文件。

      (3)运行阶段

  •  EX模块:根据译码阶段的结果,进行指定的运算,给出运算结果。相应ex.v文件。
  •  DIV模块:进行除法运算的模块。

    相应div.v文件。

  •  EX/MEM模块:实现运行与訪存阶段之间的寄存器。将运行阶段的结果在下一个时钟周期传递到訪存阶段。相应ex_mem.v文件。

      (4)訪存阶段

  •  MEM模块:假设是载入、存储指令,那么会对数据存储器进行訪问。

    此外,还会在该模块进行异常推断。相应mem.v文件。

  •  MEM/WB模块:实现訪存与回写阶段之间的寄存器。将訪存阶段的结果在下一个时钟周期传递到回写阶段。相应mem_wb.v文件。

      (5)回写阶段

  •  CP0模块:相应MIPS架构中的协处理器CP0。
  •  LLbit模块:实现寄存器LLbit。在链接载入指令ll、条件存储指令sc的处理过程中会使用到该寄存器,第9章会详述。
  •  HILO模块:实现寄存器HI、LO,在乘法、除法指令的处理过程中会使用到这两个寄存器,第7章会详述。

      另外,另一个CTRL模块。这个模块是用来控制整个流水线的暂停、清除等动作,所以不便于将其归入流水线中的一个阶段,在图3-5的上部单独画出。相应ctrl.v文件。

      本书的附录A给出了各个模块的接口示意图,及接口的作用描写叙述。读者可能会感觉模块太多、每一个模块的接口也太多。似乎非常难理解,这样的操心是不必要的,之前也提到本书不是一次实现上述所有模块,而是首先实现当中一部分模块,这一部分模块也仅仅实现少量接口,仅仅要能满足我们的要求就可以,然后随着OpenMIPS实现的指令种类越来越多,慢慢加入模块、添加接口。

3.4 实现方法

      在写作本书之前,已经出现了一些介绍软核处理器实现的书籍,这些书在介绍实现方法时有一个共同点:一次考虑全部的指令、全部的情况,然后给出代码。笔者觉得这不是一种读者易于接受的方法,并且这也可能不是作者实现处理器时採用的方法。在本书中,笔者借鉴了软件开发中的“增量模型”。使用了一种全然不同的实现方法:先考虑最简单的情况,给出代码。然后考虑略微多一点的情况,改动、补充代码,随着考虑情况的增多,不停地改动、补充代码,终于,实现需求。

      在第4章中,我们就考虑了一种最简单的情况——仅仅实现一条指令。这条指令是逻辑“或”指令ori,借助这条指令,能够搭建OpenMIPS流水线的结构,此时的数据流图如图3-6所看到的。读者临时不用理解其详细含义,仅仅需与图3-7对照。体会各自的复杂度,详细含义会在第4章介绍。


      在兴许章节中我们依次实现逻辑操作指令、移位操作指令、空指令、移动操作指令、算术操作指令、转移指令、载入存储指令、协处理器訪问指令、异常相关指令。终于实现了MIPS32指令集架构中定义的全部整数指令。此时的数据流图如图3-7所看到的。相同。读者此时暂不用理解其详细含义,仅仅需与图3-6对照,体会各自的复杂度。


      对照图3-6、3-7。会发现复杂度大大添加,假设笔者一開始就考虑实现图3-7所看到的的数据流图,那么读者须要知道MIPS32指令集中定义的全部的指令,还要理解其作用。

显然会添加理解难度。

更好的方法是,一開始仅仅考虑图3-6所看到的的数据流图,读者仅仅须要理解指令ori的作用,然后一步步加入实现很多其它指令,同一时候丰富完好数据流图,终于实现图3-7所看到的的数据流图。

比方:在加入实现转移指令的时候。就会为图3-6数据流图中的译码阶段添加“转移推断”模块;在加入实现异常相关指令的时候,就会为图3-6数据流图中的訪存阶段添加“异常推断”模块。

      以上就是本书在实现OpenMIPS处理器时採用的实现方法,下一章将实现最小结构。仅仅考虑运行一条指令ori。


未完待续!

OpenMIPS具体的模块连接关系图能够在http://download.csdn.net/detail/leishangwen/7667697下载


版权声明:本文博客原创文章。博客,未经同意,不得转载。

原文地址:https://www.cnblogs.com/lcchuguo/p/4632246.html