开放式CPU设计与测试实验报告.docx
《开放式CPU设计与测试实验报告.docx》由会员分享,可在线阅读,更多相关《开放式CPU设计与测试实验报告.docx(50页珍藏版)》请在冰豆网上搜索。
开放式CPU设计与测试实验报告
清华大学
计算机科学与技术系
计算机专业实践报告
专题名称:
开放式CPU设计与测试
课题名称:
串行、两级流水、五级流水CPU设计与测试
1.引言
1.1实验目的
1.本实验以计算机硬件为主,兼顾计算机软件和计算机应用技术。
在教师指导下,灵活运用所学到的基础知识和主要专业知识,自己设计、制作、调试,完成一个综合性、研究型的大型教学实验——16位微处理器研制。
2.本实验需要自己设计并最终用FPGA实现一个CPU芯片。
需要自己设计指令系统、指令格式、寻址方式、寄存器结构、数据表示方式、存储器系统,自己设计运算器、控制器和流水线结构等。
用VHDL硬件语言进行逻辑设计,采用先进的工具软件进行模拟和测试,测试通过之后下载到FPGA芯片中,并在测试平台上通过规定测试程序的测试。
3.在完成实验的过程中锻炼和提高实际动手能力、创新思维、团队合作精神等方面的能力。
4.本实验作为一个重要的教学实践环节,安排在本科生在课程教学基本完成之后,在综合论文训练之前,具有承上启下的作用。
5.可能的应用前景:
由于我们实现的是通用CPU,故大部分需使用CPU的场合都有可能使用,只不过目前只能用于对速度要求不高、对特殊指令要求不多(非专用CPU)的场合下。
但由于其成本比较低,在低端市场也许有一定的竞争力。
1.2国内外研究现状
CPU在全球半导体工业中扮演着一个举足轻重的角色。
大大小小,林林总总的CPU被应用到从电子表到航天飞机等各式各样的系统产品中。
从功能粗分,CPU可以被分为通用型CPU、嵌入式CPU与专用型CPU三类。
下边就先讲一下国际上这几类CPU的现状:
1.通用型CPU
通用型CPU是指用于PC的X86系列(Intel,AMD)等,及最尖端用于工作站、伺服器的UltraSparc(SUN Microsystem),Alpha (DEC),Itanium(HP+Intel)系列等。
这些CPU通常采用32位或64位指令,由宠大的研发团队(500人至2000人)设计,采用了全球最尖端的微处理器体系结构与电路设计技术,使用最先进的半导体工艺(如0.13微米-0.18微米)制成,工作时钟频率可达1GHZ-2GHZ。
2.嵌入式CPU
嵌入式CPU是指那些用于非计算机类产品(如通讯产品,消费类产品及军用产品)的CPU。
它们以独立集成电路芯片的形式存在,或作为内核被集成到系统级芯片(SOC)中。
与通用型CPU相比,它们并非追求最高的性能,而是“够用就行”。
它们通常使用主流的半导体工艺(如0.25微米-0.5微米)制成。
指令在4位到64位之间,工作时钟频率在几KHZ到几百MHZ之间。
这类CPU所含盖的范围非常之广,如广泛用于工业控制家用电路的Z80,8051,6502等;用于手机的ARM等;用于游戏机的MIPS等;都是其典型代表。
这类CPU通常采用传统的指令集。
3.专用型CPU
专用型CPU是指那些为了某种特定的应用而设计的并为这些特殊应用而将内部体系结构与指令集作了专门优化的CPU,如用于多媒体应用的媒体CPU(Media Processor)用于路由器等网络通讯产品的网络CPU(Network Processor或称NPU),及用于网络安全保障,数据加密解密的安防CPU(Security CPU)等。
时钟频率为几百MHZ。
在最近两年多的时间里,国产CPU如雨后春笋,2001年3月,中星微系统公司开发出数码影像处理芯片"星光1号";2001年7月,方舟公司的"方舟1号"嵌入式CPU问世;2002年9月,中科院计算所研制成功我国首款通用高性能CPU"龙芯1号";2002年11月,上海复旦微电子公司推出高性能嵌入式32位微处理"神威1号";2002年12月,北京大学"众志1号"面世;2003年2月,上海交通大学的"汉芯1号"面世……最值得一提的是我们清华大学于2003年7月成功研制出了自己的CPU——THUMP107,它拥有自主知识产权,是一款32位高频、低功耗的嵌入式CPU芯片,它基于MIPS4KC架构,采用0.18微米CMOS工艺,定点字长32位,主频典型频率400兆赫兹,最高主频可达500兆赫兹,功耗小于0.5瓦,实测定点运算速度可达每秒4.44亿次。
像我们完成的这个开放式FPGA-CPU的实验,在网上搜索没有发现国外有同类的课程。
大部分都是作为ComputerArchitecture课的一个实验来完成,但完成的情况基本上就是用VHDL或者VERILOG进行描述模拟就结束了。
没有像我们这样有硬件实验平台来测试完成。
国内类似课程,其它学校听说的不多。
清华本校倒是有一些类似的课程。
首先,我们计算机系《计算机组成原理》课的实验,是在TEC-2000上完成一个8位CPU的设计。
但该实验不用FPGA实现,不过该实验的SRT项目就是用FPGA完成的,与本实验极为类似。
另外,电子系大二的暑期电子实践,也是完成一个CPU的设计,用CPLD实现,与本实验也极为类似。
所以比较而言,我们的实验做到了软硬结合,既用硬件描述语言VHDL对CPU的结构和功能做了设计描述和功能模拟仿真,又烧到了FPGA上进行硬件的测试,锻炼了软件硬件两方面的能力。
比大部分学校只完成软件仿真就结束的方法对学生的锻炼和提高更大。
而TEC-2000的实验也有类似问题,该实验采用比较原始的硬件方法实现,运用先进软件工具的地方几乎没有,这有些不符合时代潮流,不符合现代电子工艺开发的流程。
而我们的这个实验就体现了这方面的先进性,对学生的培训更有实际意义。
1.3实验环境
1.总体描述
FPGA-CPU设计平台能够支持下载到FPGA中的CPU的单步调试和连续运行。
用户用VHDL编写的CPU代码通过编译之后,可以下载到设计平台上的FPGA芯片中。
FPGA-CPU的运行通过执行预先写到外部存储器中的程序来实现。
使用DebugController程序对外部存储器进行读写操作,并能监控FPGA-CPU的状态和通过设置断点调试FPGA-CPU正在执行的程序。
这套实验环境为实验者提供了最大的自由度来写出具有自己风格的CPU软核,并在测试运行平台上调试和运行。
2.硬件环境
整个硬件平台主要有PC监控系统、外部程序存储器、FPGA-CPU及其下载相关电路,以及控制电路组成。
其中PC监控系统主要是由监控软件DebugController及相关通信接口等构成,提供一整套的运行和调试功能。
见图1:
图1FPGA-CPU设计平台总体结构图
3.软件环境
1)监控程序DebugController
使用该软件对外部存储器进行读写操作,并能监控FPGA-CPU的状态和通过设置断点调试FPGA-CPU正在执行的程序。
2)Active-HDL4.2
我们用该软件做功能仿真。
该软件编译时间短,并可以查看中间信号,因此模拟、调试十分方便。
这对于检测并纠正逻辑错误是很有利的。
美中不足的是,它无法进行有效的时序模拟。
3)Quartus-4.1
我们使用该软件完成编码工作,并在active-hdl功能模拟通过后,进行有效的时序模拟。
最终烧片等都用该软件。
1.4主要成果
1.我们按照由简单到复杂的开发顺序,共开发了三个版本的CPU。
先后分别为:
串行指令CPU,两级流水CPU,五级流水CPU。
其中串行指令CPU的开发费时最长,从8月13号开始一直到8月26号才最终完成;碰到的问题最多,但学到的东西得到的经验也是最多的。
有了这个版本的开发经验,我们后两个带流水的版本都完成的非常快。
第二个版本我们做了两级流水,从设计到编码到调试,总共花了不到两天的时间,从8月27号开始做,到28号下午就测试通过了。
第三个版本我们做的是五级流水,虽然复杂了许多,但有了前两个版本的经验,我们从8月30号开始设计,到9月1号就测试完成了。
2.我们实现的每个版本的CPU都有着一个共性,那就是简洁性。
我们各个版本的从设计到编码都遵循着助教的那个“简单的就是最好的”的原则。
在这个原则的指导下,我们的每个版本的结构设计都非常简单清晰。
由此而来,我们的代码编写也极为简洁。
各个版本的代码行数分别为
串行指令CPU:
不到400(396行)
两级流水CPU:
不到700(681行)
五级流水CPU:
不到800(793行)
3.我们的每个版本的CPU都支持丰富的指令集,而且有着良好的可扩展性。
具体见第二部分的各版本的指令系统,而且为了表现的可扩展性,我们在两级流水中扩展实现了新指令LOADH,LOADL,在五级流水中扩展实现了ADDIDR,IMM(立即数和寄存器相加),SUBDR,IMM(寄存器和立即数相减),STORE2DR,OFFSET,SR(SR[DR+OFFSET]),LOAD2DR,SR,OFFSET([SR+OFFSET]DR)等指令。
4.我们的创新性成果散布在开发的各个过程中,在解决一个个问题的过程中,很多方法都是我们独创的。
比方说,在两级和五级流水中,对涉及到控制相关的JRX的处理。
再比如在五级流水中涉及到LOAD的数据相关的处理等。
都采用了与众不同的做法。
具体参见第二部分的详细设计。
2.设计报告
[注]:
这一部分的文档格式与要求的略有不同,原因是我们实现了三个版本的CPU。
所以我们的2.2和2.3并不是原来要求的“总体说明”和“各部分说明”,将2.2改为“串行指令CPU部分”,将2.3改为“两级流水CPU部分”,并增加了2.4“五级流水部分”。
在2.2,2.3,2.4的内部各自包含每个版本CPU的“总体说明”和“各部分说明”,只是我们的设计方法为TOP-DOWN,按流程描述会更清楚点,所以各部分内也没有以“总体说明”和“各部分说明”为标题,具体而言,我们文档中的“系统级设计”和“结构级设计”中的“CPU整体逻辑结构”相当于要求中的“总体说明”,“结构级设计”中的“各关键分模块设计”相当于要求中的“各部分说明”。
为了表达流畅,所以更改了文档结构,请见谅。
2.1实验方法
我们遵循的基本原则是从简单到复杂,在没有任何经验的时候,先从模拟计算机组成原理实验(也就是最初那个串行指令版本)入手,增长经验值,让我们对整个流程先有一个体验和认识。
然后再做带流水的复杂版本,具体实现时,我们最后又完成了两级流水和五级流水两个版本的CPU。
在做每个版本的设计时,我们都是遵循自顶向下(Top--Down)原则,具体而言是按如下的抽象级别设计的:
图3TOP-DOWN设计流程
后续的详细设计方案都是按这一流程完成的。
其中逻辑级,也就是用硬件描述语言描述的部分以及物理级都属实现部分。
故在本实验报告第二部分——设计报告中只描述系统级和结构级的设计。
2.2串行指令CPU部分
2.2.1系统级设计
2.2.1.1指令系统
指令系统设计的好坏影响整个系统各个方面的性能。
正如李兆麟博士所讲,现存的指令系统都是经过数十年沉淀留下来,整个行业界也仅有屈指可数的那么几套指令系统。
因此,我们在短短几个星期之内不大可能设计出一套优秀的指令系统出来。
基于此,我们采用我们清华设计CPU时走的路线——走兼容路线。
计原实验中的TEC-2000所用的就是基本与x86兼容的一套指令系统系统。
所以我们采用了基本与TEC-2000相同的指令系统[1],也增加了一些特殊的指令如HALT(停机),NOP(空操作)等,设计目标要保证指令的可扩展性。
如表1:
汇编语句
操作码
功能描述
指令类型
ADDDR,SR
00000000
DR+SRDR
算术逻辑指令
SUBDR,SR
00000001
DR-SRDR
DECDR
00000010
DR-1DR
INCDR
00000011
DR+1DR
CMPDR,SR
00000110
DR-SR比较
ANDDR,SR
00000111
DRandSRDR逻辑与
ORDR,SR
00001000
DRorSRDR逻辑或
XORDR,SR
00001010
DRxorSRDR异或
TESTDR,SR
00001011
DRandSR,测试
SHLDR
00001100
逻辑左移,最低位补0,最高位移入C
SHRDR
00001101
逻辑右移,最高位补0,最低位移入C
SARDR
00001110
算术右移,最高位右移,同时再用自身的值填入
MOVDR,SR
00001111
SRDR
数据传送指令
LOADDR,SR
01000001
[SR]DR
STOREDR,SR
01000010
SR[DR]
MOVIDR,IMM
01000011
IMMDR(双字指令)
PSHF
01000100
FLAG入栈
POPF
01000101
FLAG出栈
PUSHSR
01000110
SR入栈
POPDR
01000111
出栈DR
JRADR
00010000
无条件跳转到ADR,ADR=原PC值+OFFSET
控制转移指令
JRCADR
00010001
当C=1时,跳转到ADR,ADR=原PC值+OFFSET
JRNCADR
00010010
当C=0时,跳转到ADR,ADR=原PC值+OFFSET
JRZADR
00010011
当Z=1时,跳转到ADR,ADR=原PC值+OFFSET
JRNZADR
00010100
当Z=0时,跳转到ADR,ADR=原PC值+OFFSET
JMPAADR
01010000
无条件跳转到ADR
RET
01010001
子程序返回
CALLADR
10000000
调用首地址在ADR的子程序(双字指令)
NOP
11000000
空操作
其他
HALT
00010000
11111111
停机(JR0XFFFF)
表1串行指令CPU的指令系统
2.2.1.2时序设计
由于是串行指令系统,为了方便实现,我们实现的是多周期CPU。
那么如何区分各个周期呢?
经过分析,需要周期数最长的一条指令CALL需要6个周期,为此我们设计了一个StateGenerator,用于产生标记各个时钟的状态(共有8个状态)。
根据指令类型的不同,所有指令按执行的时钟周期数可划分成三类:
三周期指令:
包括所有的算术逻辑指令:
ADD,SUB,DEC,INC,CMP,AND,OR,XOR,TEST,SHL,SHR,SAR。
除了绝对转移指令JMPA外的所有控制转移指令:
JR,JRC,JRNC,JRZ,JRNZ。
一条数据传送指令:
MOV。
这些指令只需三个周期就可以完成,其中,前两个周期用于取指。
这些指令都可以用操作码前两位都是00,所以很容易和其它指令区别。
见图4:
图4三周期指令时序图
四周期指令:
操作码前两位为01。
包括访存指令:
STORE,LOAD,PUSH,POP,PUSHF,POPF。
立即数送寄存器指令:
MOVI。
绝对跳转指令:
JMPA。
还有子程序返回指令:
RET。
见图5:
图5四周期指令时序图
六周期指令:
操作码前两位为10。
目前仅有CALL指令一条。
见图6:
图6六周期指令时序图
全部指令的状态转换图如下:
图7串行指令状态转换图
2.2.2结构级设计
2.2.2.1数据通路
数据通路需要认真设计,因为整体结构等设计都需要依据数据通路。
我们手工画了上述指令中每个分组的一些代表性的指令,并据此有了cpu的结构设计。
但感觉数据通路的灵活性上有待进一步改进,以期达到更好的指令可扩展性。
图8load指令数据通路图
2.2.2.2整体结构设计
我们在设计整体结构时,依据的是各指令的数据通路。
然后采用自顶向下,逐步分解细化的方法进行设计。
先整体模块,后局部模块。
●CPU整体结构
图9串行指令CPU整体结构图
整个CPU由下边几个模块组成:
控制器:
在每个时钟周期给出cpu其它部件的控制信号。
具体结构见2.2.3各分模块结构设计。
运算器:
本运算器包括寄存器堆。
具体结构见2.2.3各分模块结构设计。
BusMUX:
通过控制信号BusSel数据的来源,通过Wr来控制送往外部数据总线上的数据内容。
具体结构见2.2.3各分模块结构设计。
AR(地址寄存器):
驱动地址总线。
IR(指令寄存器):
存放根据当前PC值取得的指令。
2.2.2.3各分模块结构设计
●控制器结构
图10串行指令CPU控制器结构图
控制器由两部分组成,第一个组成部分是StateGenerator,产生前边所说的用于区分执行每条指令时的各个时钟周期。
这部分的编码比较关键,为了减少尖峰,应该使得状态之间的变化仅改动一位。
如四周期指令的状态变化是这样设计的:
000010110100000。
第二个组成部分是Decoder,也就是译码器。
根据指令操作码以及FLAG(用于条件跳转)和所处的状态(state)译出该指令在本状态下的所有控制码。
译出的控制码包括:
SelSrc[2..0]:
选择参加ALU运算的数据源。
SelOpr[3..0]:
选择ALU所应执行的运算类别。
SelDst[2..0]:
选择ALU运算结果的去向。
主要完成:
1.选择ALU运算结果的来源,是ALU的运算结果还是A口的数据.
2.选择要写回的数据。
SCI[1..0]:
给出产生何种进位的控制信号。
SST[1..0]:
给出送那种类型的C,Z,V,S到FLAG寄存器。
SA[3..0],SB[3..0]:
给出寄存器组的选择信号。
BusSel[1..0]:
选择BUSMUX的数据来源。
Wr:
给出读写内存的信号。
AISel[1..0]:
选择AR或IR接收,因为AR,IR都是在时钟下降沿接收,故需要控制码来区分。
见表2:
AISel
操作
00
AR接收
01
IR接收
其它
不接收
表2AISel控制信号
其它控制信号相应组合的意义见下边各模块说明。
●运算器结构
图11串行指令CPU运算器结构图
运算器的设计参考了AM2901,但也做了较大改动,尤其是算术逻辑单元,完全是以另外一种思路来设计的。
该运算器包括两部分,第一个组成成分是一个16位的算术逻辑部件,两路输入分别用R,S标记,最低位信号Cin由外部输入控制信号SCI来产生:
SCI
CIN
00
0
01
1
10
C
11
表3SCI控制信号
它能够实现R+S,S-R,RANDS,RORS,RXORS,SHLS,SHRS,SARS8种功能,但为了保证可扩展性,选择运算类别的控制信号SelOpr由4位组成,共可产生16种运算类别,这一扩展性能在做两级流水时用到了。
如下表:
SelOpr
功能
0000
R+S
0001
S–R
0010
RANDS
0011
RORS
0100
RXORS
0101
SHLS
0110
SHRS
0111
SARS
表4SelOpr控制信号
它的输出为F,还送出向高位的进位信号C,溢出标志信号V,最高位状态信号F15(可能用作符号位),以及运算结果为零的标志信号Z。
该运算器的第二个组成成分是FLAG寄存器,它由外部的控制信号SST控制选择四位标志运算状态的信号的来源,如下表:
SST
C
Z
V
S
00
HOLD
01
UPDATE(来源为算逻部件产生的C,Z,V,S)
10
总线
表5SST控制信号
该运算器的第三个组成成分是由16个16位的通用寄存器组成的寄存器组。
它是一个用双端口(A口和B口)控制读出,单端口(B口)控制写入的部件。
两路读出数据分别用A口B口标记,经锁存器线路可以送到ALU的R,S输入端的多路选择器,A口读出数据还可以用做该运算器的可选输出来源之一。
该运算器的其余组成部分是两个多路选择器。
一个用于选择ALU部件R,S入口的数据来源,由SelSrc控制,如下表:
SelSrc
R
S
001
A
B
011
0
B
100
0
A
101
D(外部数据)
A
111
D(外部数据)
0
表6SelSrc控制信号
另一个多路选择器用于选择该运算器的数据输出是A口数据还是ALU的输出Y,同时还作为写回口B口的数据选通,由SelDst控制。
如下表:
SelDst
RegB
Y
00
F
01
F
F
10
F
A
11
A
表7SelDst控制信号
●BUSMUX结构:
通过控制信号BusSel数据的来源,通过Wr来控制送往外部数据总线上的数据内容。
结构图如下:
图12BusMux结构图
各控制信号的意义如下:
BusSel
操作
00
外部总线数据到ALU
01
ALU结果到外部总线
10
OFFSET到ALU
11
FLAG到外部总线
表8BusSel控制信号
Wr
操作
0
ALU结果送外部总线,写内存
1
高阻送外部总线
表9Wr控制信号
2.3两级流水CPU部分
2.3.1系统级设计
2.3.1.1指令系统
两级流水的指令系统比上一个串行指令系统有如下改动:
●增加指令LOADHIMM,LOADLIMM。
增加这两条指令的主要功能是处理流水线指令系统中指令字必须定长的要求。
这样,在串行指令系统中的双字指令,向MOVIIMM,在流水线指令中就可以拆成LOADHIMM高8位,LOADLIMM低8位来做了。
而且这样改动之后,通过更该配置文件可使这一变化对用户透明,具体可更改配置文件如下:
LOADHIMM"00100000[u8]",IMM
LOADLIMM"00100001[u8]",IMM
MOVIDR,IMM"00100001[u8]00100000[u8]00001111[u4]1111",(IMM)%256,(IMM)/256,DR
●去掉了Call,Ret指令。
去掉CALL指令是为了保证两级流水线结构的简洁性。
因为CALL指令在流水的第二级执行中,需要4个时钟周期才能完成。
而其它指令至多需要两个时钟周期就可以完成(这是我们精心设计时序分配关系的结果)。
而且CALL指令基本可以由其它基本指令来描述,所以,我们去掉了CALL指令,并相应的去掉了RET。
下边就是我们两级流水中的指令系统:
汇编语句
操作码
功能描述
指令类型
ADDDR,SR
00000000
DR+SRDR
算术逻辑指令
SUBDR,SR
00000001
DR-SRDR
DECDR
00000010
DR-1DR
INCDR
00000011
DR+1DR
CMPDR,SR
00000110
DR-SR比较
ANDDR,SR
00000111
DRandSRDR逻辑与
ORDR,SR
00001000
DRorSRDR逻辑或
NOTDR
00001001
/DRDR逻辑非
XORDR,SR
00001010
DRx