MIPS流水线处理器模拟仿真实验程序的设计与实现

(整期优先)网络出版时间:2023-02-07
/ 3

MIPS流水线处理器模拟仿真实验程序的设计与实现

孟海涛

320902197109012514

摘  要:流水CPU工作原理是计算机系统组成原理教学中的难点,大多教材都是基于MIPS的经典流水线处理器架构。为了更好地深入理解指令流水线的工作原理,本文结合C++面向对象程序设计技术,设计并实现了MIPS流水线模拟仿真实验程序。模拟仿真程序可以按周期模式和指令模式运行,输出显现每个机器周期的各个寄存器与存储单元的数据变化结果,并能统计不同机器指令程序的各个阶段执行效率。 

关键字:MIPS;流水线;模拟

计算机组成原理是计算机科学与技术专业的核心基础课程,同时也是一门公认的难学难教的课程[1],具有理论性强、难度大、内容抽象、实践性强等特点[2],特别是微处理器流水线指令执行过程学生难以理解。目前市场上的大部分计算机组成原理实验设备也缺乏相关实验项目,少部分也是采用FPGA平台,采用HDL语言实现,不适合学时有限且未开设FPGA课程的地方院校计算机专业[3]。因此,使用C++设计一个MIPS微处理器五级流水线模拟器,可以执行MIPS简单指令集汇编程序,输出每个周期流水线各个功能单元的寄存器内容、利用率和程序执行的总周期数,用于计算机系统结构的本科生和研究生教学[5]

1 MIPS微处理器流水线技术及指令系统

1.1 MIPS五级流水线

经典的MIPS流水线处理器是五级流水线,把数据路径分为取指(IF)、译码(ID)、执行(EX)、访问(MEM)和写回(WB)五个阶段[4]

MIPS处理器五个执行阶段的功能:

(1) IF(Instruction Fetch):取指令。从指令存储器(InstructionMemory)中取出下一条指令。

(2) ID(InstructionDecode):指令译码。对指令进行译码,分别提取操作码和操作数,从寄存器(Registers)中读取数据。

(3) EX(Execute):执行运算。执行指令操作或计算数据存储器地址(DataMemory)。

(4) MEM(Memory Access):存储器操作,对数据存储器进行数据读或者写操作。

(5) WB(WriteBack):写回。指令操作完成后,将运算结果写回寄存器中。


在MIPS五级流水线中,每个阶段都在一个时钟周期内完成(不考虑EX中的浮点运算、整数乘除以及各种冲突(Hazard)),多条指令流水线执行时序如图1所示。在T4时刻流水线装满五条指令。

图1 MIPS五级流水线指令执行时序

1.2 MIPS指令系统

MIPS指令集合一共31条指令,指令长度为固定的32位二进制编码,分为三种类型:R型格式(Register format)、I型格式(Immediate format)、J型格式(Jump format)。格式中Op是描述基本操作功能的指令操作码编码,长为6bits;Rs是第一源操作数寄存器,长为5bits;Rt是第二源操作数寄存器,长为5bits;Rd是目的操作数寄存器,长为5bits;Shamt是位移次数立即数,长为5bits;Function是功能码,长为6bits;Address是跳转目标地址,长为26bits,与PC高四位与其拼接成32bits内存转移地址。

2 MIPS微处理器流水线模拟器设计

模拟器主要是准确模拟汇编程序在MIPS微处理器流水线上的执行过程中的每个阶段寄存器和相应数据存储器单元的内容变化,不考虑其他硬件细节,如时钟触发信号、控制信号等。模拟器输入MIPS汇编程序、执行模式等,输出指令执行的每个阶段的寄存器值、每个阶段的有效利用周期数和效率。

2.1模拟器实现的 MIPS指令

模拟器选取30条MIPS指令仿真,模拟器直接读取指定汇编程序文件,将其翻译为二进制机器语言文件,存放指令存储器(InstructionMemory)中。

2.2 MIPS微处理器五级流水线的模拟

(1)硬件模拟,如表1所示。其中算术逻辑单元(ALU)的功能使用C++中对应的算术运算(+、-)、移位运算(<<、>>)、位运算(&、|、~|、^)实现。

表1 C++模拟硬件

硬件

C++模拟

IF_PC

static unsigned long int PC; //PC是32bits

IF_Add

PC+4; //指令地址递增

IF_InstructionMenory

unsigned char IMem[2048]; // 2KB指令存储器

ID_Registers

static unsigned long int R[32]; //寄存器32bits

ID_Sign extend

If(Instr[15]) sign_extend_out = Instr[15-0] | 0xffff0000;

Else sign_extend_out = Instr[15-0];//符号扩展32bits

EX_Shift left2

Shift lift2 <<2;

EX_Add

NextPC+Shift lift2 <<2;//转移指令地址计算

EX_ALU

根据指令实现算术、逻辑或移位运算

MEM_DataMemory

unsigned char DMem[2048]; // 2KB数据存储器

(2)五级流水线模拟。整个流水线由IF、ID、EX、MEM和WB五个阶段组成[6],通过4个接口连接:IF/ID、ID/EX、EX/MEM、MEM/WB。为了便于软件模拟,添加了op操作码传递,使每个阶段知晓当前的操作,实现操作功能控制。IF/ID接口将op操作码、下一条指令地址NPC和取出的指令IR,从IF阶段传递给ID阶段;ID/EX接口将op操作码、NPC、第一源寄存器数据A、第二源寄存器数据B、扩展后的立即数Imm、目的寄存器rt和目的寄存器rd,从ID阶段传递给EX阶段;EX/MEM接口将跳转指令地址Output1、ALU运算结果Output、cond、源寄存器数据B、回写寄存器地址rt/rd、op操作码,从EX阶段传递到MEM阶段;MEM/WB接口将回写数据数据存储器读出数据LMD、ALU运算结果Output、op操作码,从MEM阶段传递到WB阶段。各个阶段的操作如下:

IF阶段操作:

IF/ID.IR<--IMem[PC];

If((EN/MEM.op是分支转移)&&EX/MEM.cond)//满足转移条件

{IF/ID.NPC,PC<-EX/MEM.Output1;}

else

{IF/ID.NPC,PC<-PC+4;}

ID阶段操作:

ID/EX.A <-R[IF/ID.IR[25-21];//读rs

ID/EX.B <-R[IF/ID.IR[20-16];//读rt

ID/EX.NPC <-in>

ID/EX.Imm <-SignExtend(IF/ID.IR[15-0]);//16位立即数扩展为32位

EX阶段:

ID/EX.op <-if>

if(ALU的R指令)EX/MEM.Output <-id>

if(ALU的I指令)EX/MEM.Output <-id>

if(lw/sw) //DMem读写指令

{EX/MEM.Output<-ID/EX.A op ID/EX.Imm;

EX/MEM.B <-ID/EX.B;}

if(分支转移指令){EX/MEM.Output1 <-ID/EX.NPC+(ID/EX.Imm<<2);

EX/MEM.cond <-(ID/EX.A == 0);}

MEM阶段:

MEM/WB.op <- ex>

if(ALU相关指令)MEM/WB/Output <- ex>

if(DMem读访问指令)MEM/WB.LMD <- dmem[ex>

if(DMem写访问指令)DMem[EX/MEM.Output] <- ex>

WB阶段:

if(ALU的R指令)R[rd]<- mem>

if(ALU的I指令)R[rt]<- mem>

if(lw指令)R[rt] <- mem>

根据上述,设计一个指令类,类中实现五个阶段的操作(成员函数);设计四个接口类,分别定义四个对象IF/ID、ID/EX、EX/MEM、MEM/WB,实现五个阶段的数据传递,如下所示。

指令类描述Class MISPSimulator。

接口类:IF/ID:+NPC,+IR

ID/EX:+op,+A,+B,+Imm,+NPC

EX/MEM:+op,+B,+Output,+cond,+Output1

MEM/WB:+op,+LMD,+Output

(3)流水线冒险解决

流水线冒险是由于在流水线上执行的指令是相关的,当前后指令存在数据、硬件访问冲突或单个阶段操作需要多机器周期时会造成流水线阻塞的现象。假设每个阶段都在一个时钟周期内完成,且对寄存器写在前半时钟周期完成,寄存器读在后半时钟周期完成。流水线模拟不支持数据转发和指令无序执行。

结构冒险(Structure hazard)解决

因为MIPS流水线具有指令存储器和数据存储器,且寄存器写在前半时钟周期完成,寄存器读在后半时钟周期完成,所以解决了硬件访问冲突造成的结构冒险。

数据冒险(data hazard)解决

数据冒险是由相邻指令或间隔一条指令存在寄存器数据读写相关引起,如图2所示。由于不支持数据转发,可用延时法解决数据冒险,即流水线暂停(pipeline stall)。要判断当前指令是否与前指令发生数据冒险,需要在指令译码阶段ID判断指令是否读取的寄存器与处于EX、MEM阶段指令写的寄存器相同,因此在ID阶段需要IF、EX、MEM阶段指令内容来实现指令解码和判断数据冒险。图2(a)描述两条相邻的指令存在读写数据相关,仅发生在ID与EX阶段,图

2(b)描述间隔相邻指令发生数据冒险。

    (a)                              (b

2 数据冒险

控制冒险(control hazard)解决

控制冒险是由转移指令引起。在模拟程序中,确定分支的下一条指令的PC是在EX阶段。在这种情况下,跳转成功需要清除处于IF和ID阶段的两条指令,就会产生两个时钟周期的延时。因此跳转指令执行的时间越早,指令流水线中需要清空的指令数量就会越少。如果在ID阶段中增加检测相关控制部件、地址运算和数据逻辑运算部件,将跳转地址的计算和判断提前到ID过程段,那么流水线只需要清除一条指令,即相关的延时较少一个时钟周期。由于流水线模拟不改变MIPS流水线的结构,因此模拟程序中通过清除处于IF和ID阶段的两条指令来解决控制冒险。

(4)效率计算

各个阶段的利用率是该阶段正在做有用工作的周期的一部分。仅仅等待一个结构、控制或数据危险在它面前被清除并不构成有用的工作。所以就是用执行出冒险等待所花费的时间除以总时间就是利用率。

在程序中,设置两个变量NUM和StallNUM,变量NUM为执行有用工作周期的数量,当每个阶段顺利执行时,NUM按照每次加一的形式递增。StallNUM为执行冒险处理的周期的数量,这个周期是无用周期。当每次检测出存在冒险,程序转到冒险处理模块,处理结束时,StallNUM也是按照每次加一的形式递增。最后计算各阶段效率值,公式为:效率 = NUM/(NUM+StallNUM)。

(5)运行程序

模拟程序读入汇编程序,先编译成二进制文件,然后可选择按周期模式或指令模式运行,输出各阶段的运行结果、相应寄存器存储器内容和各个阶段的效率。图3所示,汇编文件、二进制编译文件和按指令运行模式运行2条指令的结果。

3 汇编文件、二进制编译文件、运行结果

3.结语

针对计算机组成原理课程中微处理器流水线指令执行过程难理解、实验项目缺的问题,设计流水线仿真模拟实验程序不仅解决了相应实验教学,而且具有容易理解易于实施。学生通过该模拟程序在深入理解流水线工作原理的同时,还加深了C++面向对象编程技术的学习,取得了良好的教学效果。

参考文献

[1]吴继明,钟群锋,曾碧卿.虚拟仿真技术在计算机组成原理实验教学中的应用[J].计算机教育,2019(03):34-38.

[2]潘辉,刘飞,曲海平.一种基于微程序的组成原理课程设计教学方案[J].中国现代教育装备,2019(13):48-51.

[3]兰勇,张朝阳,王伟,张少博.计算机组成原理教学改革探索与实践[J].计算机教育,2019(01):13-15+20.

[4]孙巧稚,施慧彬.基于FPGA的六级流水线MIPS处理器设计[J].微电子学与计算机,2015,32(04):31-34+39.

[5]蔡晓燕,袁春风,张泽生.MIPS架构多周期CPU的设计[J].计算机教育,2014(17):93-96.

[6]康磊.计算机组成原理——基于MIPS结构[M].西安电子科技大学出版社,2019.4

基金项目:2018年第二批产学合作协同育人项目(201802216019);2022年盐城工学院教育改革资助课题JYKT2022B041