现在都流行自制,搭着这个东风,本人制作了一个32位的处理器,采用MIPS指令级,所以叫做OpenMIPS,它是完全开源的哦,大家可以自由下载讨论,共同提高。
裸奔是危险的,裸机也是不好用的,所以本人颇费周折的为OpenMIPS移植了开源操作系统ucos-II,一方面是为了便于使用,另一方面也是为了验证OpenMIPS是否实现正确。
现在,我宣布,我的OpenMIPS+ucos-II已经在Altera的DE2评估板上成功验证(此处应该有掌声)。
为了总结历史、面向未来,特通过几篇博文记录移植的详细过程,还在探索路上的小伙伴们可以做一个参考,已经把我等甩得老远的大牛们也希望能屈尊提提意见。
计划分以下几部分:
- OpenMIPS介绍
- OpenMISP实践版及SOPC搭建
- 在DE2上验证OpenMIPS
- ucos-II文件目录建立
- 移植ucos-II时需要修改的文件
- 创建Makefile
- 在DE2上验证OpenMIPS+ucos-II
这是第一部分:OpenMIPS介绍
1 OpenMIPS项目简介
OpenMIPS开始于2013年8月,目的是开发一款32位、兼容MIPS32指令集的开源软核处理器,便于老师教学、学生体会理解计算机体系结构课程的相关知识,同时也可以做实际用途。OpenMIPS将坚持自由软件的理念,保持开源的形式,同时采用商业友好的LGPL授权。并且分为两个版本:教学版、实践版,每个版本都使用VHDL、Verilog HDL两种语言编写,这样实际是有四个版本,分别命名为(以1.0版为例)
- OpenMIPS_VHDL_study_v1.0 教学版(VHDL)1.0
- OpenMIPS_Verilog_study_v1.0 教学版(Verilog)1.0
- OpenMIPS_VHDL_practice_v1.0 实践版(VDHL)1.0
- OpenMIPS_Verilog_practice_v1.0 实践版(Verilog)1.0
教学版的主要设想是尽量简单,比如:在一个时钟周期内可以取到指令,完成存储、加载数据,这样处理器的运行情况(比如:流水线的运行)就比较理想化,与教科书相似,代码也很清晰简单,便于使用其进行教学、学术研究和讨论,也有助于各位同学理解课堂上讲授的知识。
实践版的主要设想是使OpenMIPS成为一个实际可用的处理器,能够下载到
FPGA上,运行实际有用的程序,为此,添加了Wishbone总线接口,使其可以挂接在wb_conmax互联矩阵上,这样就能方便的利用OpenCores上提供的SDRAM、Flash、GPIO、UART、LCD等模块控制器,组成一个SOPC,完成特定功能,进一步还可为其移植操作系统。
OpenMIPS是采用具有哈佛结构的32位标量处理器,兼容MIPS32体系结构,这样可以使用现有的MIPS编译环境。具有以下特点:
- 五级整数流水线,分别是:取指、译码、执行、访存、回写
- 哈佛结构,分开的指令、数据接口
- 32个32位整数寄存器
- 大端模式
- 向量化异常处理,支持精确异常处理
- 8个外部中断
- 32bit数据、地址总线宽度
- 单周期乘法
- 支持延迟转移
- 兼容MIPS32体系结构,支持MIPS32指令集中的所有整数指令
- 大多数指令可以在一个时钟周期内完成
- 可综合
- 兼容wishbone b2的指令、数据总线接口(只有实践版提供)
- LGPL开源
- VHDL、Verilog HDL两种语言版本
在我的移植ucos-II的过程中使用的是OpenMIPS实践版(VHDL),小伙伴们不吝赐教啊。
让我们为了OpenMIPS的茁长成长共同努力!
欧耶!
2 OpenMIPS支持的指令
OpenMIPS支持MIPS32指令集中的如下指令(包含全部整数指令),各指令的具体含义可以参考《MIPS32指令集》(在后面的博文中会给出OpenMIPS的下载地址,其中就有该文件)。
- 逻辑操作指令AND、ANDI、LUI、NOR、OR、ORI、XOR、XORI
- 移位操作指令SLL、SLLV、SRA、SRAV、SRL、SRLV
- 算术操作指令ADD、ADDI、ADDIU、ADDU、CLO、CLZ、SLT、SLTI、SLTIU、SLTU、SUB、SUBU、MADD、MADDU、MSUB、MSUBU、MUL、MULT、MULTU、DIV、DIVU
- 移动操作指令MFHI、MFLO、MOVN、MOVZ、MTHI、MTLO
- 控制指令NOP、SSNOP
- 跳转指令J、JAL、JALR、JR
- 分支指令B、BAL、BEQ、BGEZ、BGEZAL、BGTZ、BLEZ、BLTZ、BLTZAL、BNE
- 加载类指令LB、LBU、LH、LHU、LL、LW、LWL、LWR
- 存储类指令SB、SC、SH、SW、SWL、SWR
- 协处理器访问指令MFC0、MTC0
- 自陷指令SYSCALL、TEQ、TEQI、TGE、TGEI、TGEIU、TGEU、TLT、TLTI、TLTIU、TLTU、TNE、TNEI
- 异常返回指令ERET
3 OpenMIPS的流水线
OpenMIPS具有五级流水线(这可是经典的五级流水线哦,任何一本计算机体系结构的书籍都会介绍),在各个阶段完成的工作如下:
- 取指阶段:从指令存储器取得指令,修改pc的值
- 译码阶段:指令译码,根据译码结果取得指令执行需要的寄存器的值、立即数的值,并判断是否是多周期指令
- 执行阶段:判断并解决数据相关问题,执行指令操作,判断是否转移
- 访存阶段:如果是加载存储指令,那么读写数据存储器
- 回写阶段:写目的寄存器。判断是否有异常发生
4 OpenMIPS中的寄存器
OpenMIPS支持32个32位整数寄存器,还支持协处理器CP0中的如下寄存器:COUNT、COMPARE、STATUS、CAUSE、EPC、CONFIG、PrId、BadVAddr、ErrorEPC。这些寄存器的含义可以参考文档《MIPS32_3_Privileged_Resource》(在后面的博文中会给出OpenMIPS的下载地址,其中就有该文件),或者《MIPS体系结构与编程》、《MIPS体系结构透视(See MIPS Run)》等书籍。
5 OpenMIPS的异常模型
OpenMIPS支持精确异常模型,当异常发生时,有关处理器的状态信息被存储到协处理器CP0的部分寄存器中,然后OpenMIPS处理器转移到事先定义好的一个地址,在那个地址中往往存储有异常处理例程,在其中进行异常处理,这个地址称为异常处理例程入口地址。
具体来说,当异常发生时,OpenMIPS会进行如下操作:
(1)设置EPC寄存器:如果当前指令不在延迟槽中,那么当前指令(或下一条指令)地址被存储到EPC寄存器中,如果当前指令在延迟槽中,那么当前指令的上一条转移指令地址被存储到EPC寄存器中。
(2)设置CASUE寄存器:在其ExeCode字段存储异常原因代码,具体含义可以参考doc目录下的文档《MIPS32_3_Privileged_Resource》(在后面的博文中会给出OpenMIPS的下载地址,其中就有该文件),或者《MIPS体系结构与编程》、《MIPS体系结构透视》等书籍。
(3)设置STATUS寄存器:设置其EXL位为1,表示处理器处于异常处理状态。
(4)转移到相应的异常处理例程继续执行。
当异常处理结束后,需要使用指令eret从异常返回,eret指令会将EPC的值恢复到PC,同时设置STATUS 的EXL位为0,处理器回到异常发生前的状态继续执行。
OpenMIPS支持的异常类型及对应处理例程的入口地址如下表所示,其中无效指令、系统调用、自陷的处理例程入口地址都是0x40,用户也可以自己修改,使得这三个异常的处理例程入口地址不一样。异常的优先级也是可以调整的,小伙伴们只要理解了OpenMIPS的代码,这些都是可以灵活修改的。
异常类型 | 优先级 | 处理例程地址 | 引起异常的条件 |
复位(Reset) | 1 | 0x0 | 由软件或硬件复位引起 |
外部中断 | 2 | 0x20 | OpenMIPS支持8个外部中断 |
系统调用(System Call) | 3 | 0x40 | 使用指令SYSCALL |
无效指令 | 4 | 0x40 | 指令不是OpenMIPS支持的指令 |
自陷(Trap) | 5 | 0x40 | 使用指令TEQ、TEQI、TGE、TGEI、TGEIU、TGEU、TLT、TLTI、TLTIU、TLTU、TNE、TNEI等 |
未完待续哦!
关于OpenMIPS的实现原理,在《十天实现处理器——OpenMIPS成长记》一文中有介绍,该文档可以在论坛上下载,具体是随OpenMIPS教学版一起发布的。