CPU设计报告.docx
- 文档编号:30549655
- 上传时间:2023-08-16
- 格式:DOCX
- 页数:32
- 大小:488.75KB
CPU设计报告.docx
《CPU设计报告.docx》由会员分享,可在线阅读,更多相关《CPU设计报告.docx(32页珍藏版)》请在冰豆网上搜索。
CPU设计报告
32位CPU
本CPU是32位CPU,具有32个通用寄存器,指令包括算术加减,与或非,逻辑比较,无条件跳转以及条件跳转,内存加载与存储,体系结构属于RISC体系结构。
内部结构如下,具有两条5级的并行流水线A和B,在A中内嵌有一个执行16周期的串行乘法器,能够执行两个16位无符号数乘法运算,能够响应外部中断并执行相应中断服务程序和中断返回。
软件指令方面,扩展了指令集,所有算术指令和逻辑指令都支持第二个操作数为立即数。
跳转指令除了能够跳到一个立即数表示的偏移地址外,还能够跳转到某个寄存器里面的地址。
硬件整体结构如下:
下面将仔细说明各个模块的功能:
数据通路整体说明:
取数:
指令预取于发送部件将指令发送到取数部件,取数部件根据译码结果以及前向数据通道给出的信号决定是取立即数,寄存器堆输出或者前向数据通道给出的数据。
执行:
取数完成后,在下一个周期流到执行部件,算术和逻辑运算指令通过ALU得到结果,访存指令读或写内存,跳转指令算出新的PC地址,乘法指令将被乘数和乘数打入到乘法器的两个输入寄存器。
写回:
执行完成后,在下一个时钟上升沿将结果以及本级IR和ID送往写回部件,写回部件将要写的寄存器号和写使能信号送往寄存器堆,在下一个时钟上升沿将数据写入寄存器堆。
指令的预取与发送:
(”IRLoader.v”):
输入数据与控制信号:
RamD[63:
0]
NewPc[31:
0]
RA
LdPc
Read1,Read2
内存数据
新的PC值
是否读取Ram
加载新的PC
A与B流水线读信号
输出数据:
IR1,ID1
IR2,ID2
PC2
Adr
A路指令与译码结果
B路指令与译码结果
B路指令地址
指令在内存中地址
功能:
自动加载程序PC,LdPc有效时,给出的是两条空指令。
若Read1或Read2无效,则送往A或B的是空指令。
同时自动将乘法指令送往A流水线,将访存和跳转指令送往B流水线。
内部核心部件:
8个寄存器的指令队列,同时在某个3位的数据InsAdr标志最后一条指令在队列中地址。
另外一个Flag[7:
0]标志当前要写的寄存器,高电平有效。
每次根据发送指令的条数和从内存中读取得条数
(2)来决定InsAdr的改变(可以改变-2,-1,0,1,2)。
在加载新PC的同时将队列清空,另外,只有当队列中指令数目〉=2才能读取
【译码器】-“INS_DECODER.v”
输入为6位指令操作码INS_OP[5:
0],输出有指令译码ID[15:
0]、ALU操作码ALU_OP[3:
0]、寄存器或立即数标志RI。
ID各位对应的指令如下:
该部件属组合逻辑,不对输入和输出结果进行寄存。
【取源操作数部件】-“GET_OPER.”
该部件输出两个源操作数。
其中第一个操作数有可能是寄存器值或前向通道运算结果,第二个操作数有可能是寄存器值、立即数或前向通道运算结果。
输入包括:
(与第一个源操作数有关的)REG1[31:
0]-寄存器堆的第一个输出,FORE1[31:
0]-前向通道输出,FOR1-前向通道的标志,高有效;(与第二个源操作数有关的)REG2[31:
0]-寄存器堆的第二个输出,FORE2[31:
0]-前向通道输出,IMME[31:
0]-立即数,FOR2、RI-寄存器值、立即数、前向通道结果的选择标志,RI=1表示立即数,在RI=0的前提下,若FOR2=1,表示前向通道结果,若FOR=0,表示寄存器值。
输出即是两个源操作数OPER1[31:
0]、OPER2[31:
0]。
该部件属组合逻辑,不对输入和输出结果进行寄存。
【立即数扩展部件】-“IMME_EX.v”
该部件根据指令类型输出32位立即数,作为第二个源操作数。
所有算术、逻辑、移位指令,比较指令,加载16立即数指令,若第二个源操作数是立即数,均需将指令编码中的低16位符号扩展成32位,作为立即数。
所有跳转指令均需将指令编码中的低26位符号扩展成32位,作为立即数。
加载32位数指令需将寄存器中原低16位作为立即数的高16位,和指令编码中的低16位拼接成32位,作为立即数。
输入包括32位指令编码INSTR[31:
0]、16位指令译码结果ID[15:
0]、寄存器堆的第二个输出REG2[31:
0]。
输出即为立即数IMME[31:
0]。
该部件属组合逻辑,不对输入和输出结果进行寄存。
[取数部分发生相关]——“Relative.v”
由于CPU采用双流水线超标量结构,相关的判定和指定调度比单流水线要复杂一些。
本CPU的指定调度完全由硬件实现,对软件是透明的。
指定调度采用流水线停顿和前向数据通道结合的方式。
写回部件的输出结果由专用通路送至取数部件的输入端,立即可用,因此写回部件中的指令不会引起相关。
多周期指令,即乘法指令MUL的存在增加了相关判定和指定调度的复杂性。
设当前两条流水线的取数部件内指令为A1、B1,执行部件为A2、B2,写回部件为A3、B3。
如下图。
执行
预取指部件按时序发送指令,限定A1在B1之前进入取数部件。
由此相关判定得到一定程度的简化。
相关分为资源相关、数据相关和控制相关三种。
控制相关由跳转指令引起,只需在跳转指令的执行周期将前级指令清空即可。
下面讨论前两种相关。
1.资源相关
资源相关主要由乘法器的使用与内存访问引起。
双流水线中,乘法器与访存部件都只有一个。
乘法器在A线,访存部件在B线。
预取指部件限定乘法指令送至A线,访存类指令送至B线,大部分资源相关得到避免。
与此同时,指令访存与取指仍然存在冲突。
为此,在访存类指令的执行周期,预取指部件的内存取指需暂停一个周期。
2.数据相关
数据相关又分为RAW、WAW和WAR三种。
下面分别讨论之。
(1)RAW,写后读
这是最主要的相关类型。
RAW影响指令的取数周期,若指令读取的寄存器与执行部件写回的寄存器一致,或者是与另一条流水线取数部件的写回寄存器相同,流水线就需要停顿。
考虑到A1先于B1的限定,指令A1需考虑A2与B2的写回,指令B1则需考虑A1、A2与B2三条指令的写回。
标志寄存器的读写同样可以引起RAW相关,这引起条件跳转指令的停顿。
与数据寄存器不同,标志寄存器在执行周期被读取。
此外,跳转指令只能进入B线,因此,若B1为条件跳转,B1需考虑A1的对标志寄存器的修改。
这里还要补充说明一点,MUL不影响标志寄存器,否则乘法执行期间跳转指令将一直停顿。
当指令A1由于数据相关被暂停时,从原则上B线依然可以流通,但流水线中各指令的相对时序会被破坏。
具体而言,A1被暂停时,B1将进入执行周期,而A1本不应考虑B1的写回。
为此,当A线发生相关,两条流水线都需要停顿。
另一方面,当指令B1引起相关时,预取指部件为保证取数指令的相对时序,不可将指令送入A线,但指令A1可以进入执行周期。
对于多周期指令,即乘法,情况又有一些变化。
按照CPU的设计思路,当A2为MUL,B线在数据不相关的前提下依然可以保持流通。
这有可能破坏流水线中各指令的相对时序。
具体而言,A1将先于B2,这种情况下A1不应考虑B2的写回。
为此,控制器限定,当MUL指令被送入A流水线后,不再往A流水线送入任何指令,直到MUL结束,那么当A2为MUL时,A1为空指令。
(2)WAW,写后写
若指令序列没有按序完成,WAW有可能引起相关。
因此,WAW相关主要需考虑多周期指令MUL。
若A2为MUL,且B2与A2写回同一个寄存器,按照前面提到的各种限定,MUL一定先于B2。
这样,MUL指令就没有了执行的必要。
因此,MUL将被清除,从而消除了WAW,运算效率也得到提高。
附加说明一点,当A线与B线的写回部件写入同一个寄存器时,寄存器堆优先选取B路的输入。
因此单周期指令不存在WAW相关。
(3)WAR,读后写
只有当指令序列时序很混乱时,WAR才可能引起相关。
由于已对指令时序作了多种限定,在这里不存在WAR相关。
[ALU](“ALU.v”)
ALU的输入为32位的数据a、b以及4位的操作码op,输出为32位的结果out以及C、O、N、Z4个标志位。
ALU指令分为三类:
1.算术运算:
ADD、SUB
2.逻辑运算:
AND、OR、XOR、NOT
3.移位运算:
SHL、SHR、ASR、ROR
三类运算分别用加法器、逻辑运算器和移位器三个运算部件完成,ALU的输出由一个四选一的多路选择器从三个运算结果中选出。
ALU的结构框图如下:
下面对三个部件分别进行说明和分析
1.加法器
加法器由四个8位的超前进位加法器按组间超前进位方式级联而成。
作减法时将第二个操作数取反并令进位输入cin为1。
8位超前进位加法器从输入稳定到输出稳定需要大约6个门延时的时间,组间超前进位则需4个门延时。
加上前置的2选1多路选择器,加法与减法大约消耗12个门延时。
2.逻辑运算器
逻辑运算器完成4种简单的逻辑运算,用操作码op的低两位选取输出。
逻辑运算器约消耗3个门延时,与加法、减法相比几乎可以忽略。
3.移位器
移位器是一个32位的漏斗移位器,由两级移位器级联而成,移动位数为0~31。
按照常规的移位器方案,容易出现一个bug,那就是逻辑左移0位时,输出结果并不与输入相同,而总是0。
这是由于在漏斗移位器中,左移0位用右移32位来实现,若移动位数由5位信号来控制,移动位数最多只是31位。
第一种解决方案是由6位信号来控制移动位数,移动位数最多可达63位。
这种方案对移位器运算速度没有影响,但硬件规模有所增大。
第二种解决方案是在输入端进行控制,当移动0位时避免左移。
这种方案将增加两个附加门延时。
考虑到移位器的运算速度比加法器快一些,附加两个门延时并不影响ALU总体效率,因而采用了第二种方案。
这样,移位器共需11个门延时。
ALU的输入用操作码op的高两位从加法器、逻辑运算器和移位器的输出结果中选出,再加上标志位的生成,另需3个门延时。
因此ALU的运算时间约为15个门延时。
16位无符号串行乘法器:
(“Mul16.v”);
上图为32*32的乘法器.16*16乘法器原理上与上同,只是寄存器和ALU位数半.
输入输出接口:
moduleMult16_M(result,Busy,a,b,Load,clear_0,clk_up);
input[15:
0]a,b;//被乘数与乘数
inputLoad,clear_0,clk_up;//准备载入信号,清零信号(低电平有效),时钟
output[31:
0]result;//乘积
outputBusy;//运算状态信号,为1时表示正忙
流程:
某一时钟周期内,Load=1,加载被乘数和乘数,其中乘数加载到乘积的低16位,乘积高16位清零(否则第一次加法结果会产生错误).计数器的值初始化.
当Load降为零时,Busy=1,表示运算开始,
每个时钟周期结束乘积向右移1位.移出来的即为乘数的低到高位,分别与被乘数的每位相与,再和乘积的高16位输入到ALU
这样需要16个时钟周期.
计数器就是用移位器做的,计数初值为ffff,向右移16次后,变为0,当末尾为0时,计算即结束.此时,Busy=0表明结果可以取出.
【跳转通路】-“J_PATH.v”
该部件作为跳转指令的执行通路,输出跳转地址,属于流水线的“执行”部件。
跳转指令的操作数若为寄存器值,则寄存器值就是跳转的绝对地址,若为立即数,则立即数为相对于当前指令的指令条数。
输入包括:
RI-寄存器或立即数标志,1表示立即数;CLK-时钟;EN-寄存器写使能,高有效;PC[31:
0]-当前指令地址;OPER2[31:
0]-第二个源操作数。
输出为跳转的绝对地址J_ADDR[31:
0]。
该部件有输入寄存,但无输出寄存。
前向数据通路:
(“Relative.v”)
在解决相关的尝试中,除了在程序编写的过程中,程序员有益的安排好存在相关的语句间的顺序外,硬件上解决相关造成流水线停顿的一个重要途径就是前向数据通路,我负责Super的前向数据通路的编写。
前向数据通路是一个组合逻辑电路,由于Super是双流水线结构,所以前向数据通路有两个数据输入端,一个数据输出端;3个5位代码输入端(两个是输入数据的,一个是用于选择输出数据的);顺序优先级,由于B路流水线总在A的后面,因此如果发生RAW相关,一定取B路流水线要写的数据,也就是0号的数据优先选中;数据通道使能信号输入端;是否有匹配数据被选中信号输出端。
具体工作原理就是,根据5位的代码输入端的代码和数据通道使能信号,选择两个数据输入中的一个(0号通道优先)输出,并将匹配数据被选中信号置一,如果没有匹配的数据,则将此信号置零。
具体的实现代码这里略去。
写回寄存器:
这一级相对前面来说比较简单,由于前面不见需要用到当前指令是否需要写寄存器,因此在译码结果中ID[21]即表示是否需要写寄存器,将ID[21]连到寄存器堆Write使能端,将指令中对应得目的操作数连接到寄存器选择端即可。
另外,写后写的相关性已经由寄存器堆判定,因此此级不需要进行相关性判定。
【内存】-“RAM.v”
该部件模拟内存,通过系统任务对内存进行初始化,加载程序和数据。
输入包括:
CLK-时钟;ADR[31:
0]-内存地址;RAMI[31:
0]-向内存中写入的数据;WREN-写使能,高有效。
输出为RAMO[63:
0],即每次读出两条指令,其中顺序在前的指令放在低32位,在后的指令放在高32位;当读取数据时,仅取输出的低32位。
控制器实现:
(”CtrlUnit.v”)
主要控制:
控制本级指令是否流往下一级,注意,如果本级指令不流往下一级时,那么下一级的NOP端一定有效,即下一级的指令如果流走了,那么一定加载空指令。
输入数据:
A和B流水线3级的IR和ID,数据通路给出的信号。
输出数据:
A和B流水线3级的IR和ID使能En与NOP信号,指令预取部件的读取信号Read1,Read2,乘法器的加载信号MulLoad2A,PC加载信号LdNewPc。
控制器的设计是最困难的,虽然核心代码(除去数据定义)不到50行,但是由于它是一个时序逻辑,不仅仅需要考虑本周期,还要考虑下一个周期以及下下个周期。
从理论上来讲,需要考虑无限多个周期。
具体设计时,根据本周期的状态,主要是两条流水线的六条指令以及相应译码结果,数据相关检测给出的结果,是否跳转,乘法器是否忙来控制指令寄存器的En和NOP端,即控制指令是否需要往下一级流动,这里En和NOP有一个很强的关联,那便是上一级的En如果无效,则上一级应该往本级送NOP指令,也就是本级的NOP有效。
另外,我们的指令寄存器有个特点:
En的优先级高于NOP,即本级的En如果无效,那么便不能打入空指令,这显然是很必要的。
指令集设计:
【指令编码】
所有指令分为:
算术、逻辑、移位指令,比较、位测试指令,跳转指令,LOAD、STORE指令,立即数加载指令,MOV指令,乘法指令,空指令。
具体内容如下:
算术、逻辑、移位指令比较、位测试指令
ADD加法;CMP比较;
SUB减法;TST位测试;
AND与;跳转指令
OR或;JMP无条件跳转;
XOR异或;JEQ等于零跳转
NOT非;JNE非零跳转
SHL逻辑左移;JHE无符号大于跳转;
SHR逻辑右移;JLO无符号小于跳转;
ASR算术右移;JGE有符号大于跳转;
ROR循环右移;GLT有符号小于跳转;
LOAD、STORE指令立即数加载指令
LDR寄存器加载;LDA加载16位立即数(符号扩展成
STR写内存;32位);
MOV指令LDA32将寄存器低16位移至高16位,
MOV寄存器传送;再加载16位立即数到寄存器的低16位;
乘法指令空指令
MUL乘法;NOP
中断指令
JU从系统态跳转到用户程序;
INT软中断;
IRET中断返回。
CPU的测试结果:
(大家共同参与调试)
大规模的测试已经由陈晨与周炜做了,没有发现Bug,下面给出一个简单测试程序的波形仿真结果:
程序如下:
nop
ldar0,Begin;跳到用户态
jur0
nop
Begin:
ldar0,10
ldar1,0
Loop:
addr1,r1,r0
subr0,r0,1
cmpr0,0
jgeLoop
End:
ldar2,1234;标志结束
jmpEnd
上面计算10+9+8+----+1,结果应该是55,仿真结果如下:
第一个数据reset为系统复位
第二个数据TestN为计数器
第三个数据是CPU时钟
第四个数据是A路流水线的输出结果(将要写回寄存器)
第五个数据是B路流水线的输出结果(将要写回寄存器)
第六个个数据程序PC(由于是两路流水线,一个周期可能增加8,也可能由于相关被堵塞而增加4或0);
程序从0地址开始:
执行ldar0,Beginjur0
注意到DataOut3B输出16(Begin地址,同时程序PC也到了Begin处)。
PC增加到20后又回到16,跳转指令正确。
R0加载10
注意上面黄色线位置处为10,同时黄线在程序PC到16后的第五个5个周期出现,同时PC的值处理由20——28是增加8以外,其它都是增加4,这时由于本程序相关性较多,导致每个周期只能发送一个指令。
减1后循环:
上面R0减少到7后,R1为10+9+8=27,注意到27余7是同时出现的,说明此时两条流水线当前级都装满了指令,进行相关性分析后也确实如此。
完成10次加法:
R0=0,R1=10+9+----+1=55
从上面可以看到R1=55,R0=0,至此,10次加法结束,后面进入死循环。
从上可以看到数据流和PC在重复变化。
串行乘法器测试:
如图所示,仿真87*79,结果为6873,上下两个图是连在一起的(MulOut2A在上图的最右边和下图的最左边都是1336321),可以数出从加载数据到计算出结果正好为16个周期,表明设计是正确的.
测试结果正确。
CPU性能与效率评估:
(测试人:
陈晨)
1.对于Super的相关性整体效能,我使用了一个冒泡排序的程序进行了测试。
源程序见“冒泡排序.txt”,二进制代码见“冒泡排序_ex.txt”
用modelsim进行仿真:
可以看到,白框中的数字已经是10~1的由大到小的顺序了。
程序运行了364303ns
图中,12345就标志着排序已经完成了,时钟周期是200ns,所以整个排序过程进行了1822个周期。
由前面汇编源代码可以算出一共是(12*9+4)*10=1120条指令。
1、理论上,假设每条指令间没有相关,跳转指令不会影响流水线的流动,则Super的双发射5级流水线应该使用1120/2=560个周期完成排序算法;
2、理论上,如果是一个没有流水线的CPU,则每条指令需要5个时钟周期完成,这个排序程序一共需要5600个周期。
3、实际执行使用了1822个周期,没有达到理论预期的最佳性能,但是比没有流水线的情况要快得多。
4、加速比为5600/1822=3.07
估计原因是:
1、循环体内写后读和读后写相关较多,严重影响了双流水线的并行并且使流水线出现了中断;
2、跳转指令的存在,使得流水线不得不清空,重新装入指令。
为了验证跳转指令对流水线的影响,我又对程序进行了一定的修改,使得待排序的数列已经是排过序的数列了,也就是说在程序运行中,每个循环中不需要执行交换指令而是跳转指令,用以检查跳转指令的效率。
源程序见“冒泡排序2.txt”,
测试结果:
用了355303ns,也就是1777个周期和之前每次循环都有交换没有跳转的周期数差不多,说明跳转指令差不多相当于3条一般算术指令的运行时间。
也就是说,对于一个随机的数列的排序,使用周期在1800左右。
为了尽量避免相关,我增加了通用寄存器的使用数量,并调整了一些语句的顺序:
见“冒泡排序3.txt”
用了324500ns,也就是1623个周期,比最开始的那个程序有了一定的提高。
加速比为(12*9+4)*10*5/1623=3.45。
另外,周伟也做了选择排序的测试,循环展开后,138条语句,测试结果约为180个周期,效率和前面差不多。
至此,2条5级并行流水线的测试工作已经完全结束,在相关性较高的情况下,流水线的效率约为30%-40%。
中断控制系统:
(编写与测试人:
冯勇)
硬件中断,软件中断与中断返回控制:
(”SysIns.v”)
硬件中断与软件中断
如果是硬件中断,则锁存中断请求与中断类型号,将中断使能置为无效,等流水线流空后,保存下一条指令的PC和当前的标志寄存器Flag值,将它们存入堆栈,根据中断向量号取出中断服务程序地址,跳转到中断服务程序,开中断。
中断返回:
从堆栈里面取出程序Flag与PC值,无条件跳转到PC值对应的地址。
设计思想:
从CPU需要做的事可以看出,这绝对是一个非常复杂的工作,若用硬件来实现,将非常繁琐,并且容易出错。
注意到保存PC和Flag,将它们看作是将普通寄存器的值存入内存,用str指令很容易实现,堆栈地址递增用加4操作实现。
取中断向量号同样用ldr实现,跳转用jmp+寄存器实现,即所有的操作都可以用软件来实现。
中断返回也是同样道理。
核心设计思想:
当出现硬件中断请求,软件中断请求,IRET指令时,向当前程序流插入一条跳转指令,此指令跳转到某一段代码区(称为硬件代码区),此段代码判断请求是硬件中断,软件中断还是IRET指令。
分别执行它们需要的操作即可。
问题:
软件指令只能访问寄存器堆,不能访问程序PC以及标志寄存器,并且硬件代码执行必然会破坏当前寄存器的内容。
解决办法:
在CPU中设置两个寄存器堆,分别称为用户寄存器和系统寄存器,用某个锁存器RegSys0来标志当前是选择用户寄存器还是系统寄存器。
正常运行时,RegSys0选择用户寄存器,当进入硬件代码时,CPU将需要保存的PC以及Flag用硬连线的办法存入系统寄存器同时RegSys0切换到系统寄存器。
这是要保存的PC以及Flag能够被软件指令访问到。
并且此时使用的是系统寄存器,不会影响到程序的寄存器内容。
并且由于用户寄存器还是系统寄存器基本没有任何区别(下面会说明),硬件代码的执行和用户程序的执行没有任何区别。
系统寄存器的分配:
R24——R31不能被指令写,它们的输入与写使能是受CPU内部硬连线控制的。
但是指令能够读取R24——R31的内容。
R16——R23:
指令能够写,但是它们是作专用的,其值在系统初始化被设置好,以后就不能更改,若更改了则执行某些指令(例如硬件中断,IRET)会导致系统瘫痪。
R1——R15:
通用寄存器,硬件代码能够任意读写。
各个寄存器分配如下:
R24
R25
R26
R27——R31
中断发生时保存的PC
中断发生时保存的Flag
类型号
Unused
其中R24的输入一直连着程序PC,R25一直连着Flag寄存器,它们的使能受中断控制器的控制,在合适时候将PC和Flag打入。
R19
R20
R21
R2
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- CPU 设计 报告