CPU实验单周期MIPS处理器设计Word文件下载.docx
《CPU实验单周期MIPS处理器设计Word文件下载.docx》由会员分享,可在线阅读,更多相关《CPU实验单周期MIPS处理器设计Word文件下载.docx(9页珍藏版)》请在冰豆网上搜索。
为了综合后能够在开发板上正确运行程序,我们决定采取50MHz的CPU时钟,因此编写了一个时钟分频模块,对开发板提供的100MHz时钟进行二分频,从而得到50MHz时钟。
2、PC产生模块
原理图如下:
如上图左半部分所示,多路选择器由一个always语句中的if…elseif…else语句实现。
其中,将ALU中的加减法部分提取出来实现一个加法器,用于产生PC+4和ConBA两个PC来源。
将I型指令中的16位立即数左移两位后再符号位扩展成32位地址,与PC+4相加得到分支地址ConBA。
将跳转指令中的26位目标地址左移两位后,与当前PC的高四位拼接得到跳转地址JT。
将第一个操作数寄存器中的值取出作为PC的一个输入,这是为了实现jr和jalr指令,从$Xp和$Ra寄存器中读取跳转地址。
ILLOP和XADR分别是发生中断和异常时的跳转地址。
下一指令地址的选择由PCSrc决定,而PCSrc是译码后由控制信号模块根据每条指令的操作码(opcode)和函数码(funct)产生。
3、译码模块
原理图如上图右半部分所示,将PC作为ROM模块的地址输入,输出即为PC所对应的指令。
分别取出指令中的某些片段,得到$Rs,$Rt,$Rd,shamt,funct,16位立即数和26位跳转地址。
4、控制模块
控制模块即控制信号产生模块,六位操作码OpCode,六位函数码[5:
0]Funct,定时器中断信号irq和PC最高位PC31作为输入,输出为以下控制信号:
(1)R型指令指示信号IsR,值为1表示当前指令为R型指令,否则非R型指令;
(2)PC产生的选择信号[2:
0]PCSrc,取值0,1,2,3,4及其它,分别选择下一指令不同的PC;
(3)目的寄存器选择信号[1:
0]RegDst,被写入的寄存器有四种选择:
$Rd,$Rt,$Ra,$Xp,分别由RegDst不同取值完成选择;
(4)写寄存器使能信号RegWr,值为1表示允许对寄存器进行写操作;
(5)ALU第一个操作数选择信号ALUSrc1,值为1表示选择将移位量shamt进行0扩展后作为输入,值为0表示将$Rs寄存器中的值作为输入;
(6)ALU第一个操作数选择信号ALUSrc1,值为1表示选择将扩展后的32位立即数作为输入,值为0表示将$Rt寄存器中的值作为输入;
(7)ALU运算控制信号[5:
0]ALUFunc,作为ALU的输入选择不同的运算操作;
(8)有无符号数指示信号Sign,值为1表示有符号数,值为0表示无符号数;
(9)写存储器使能信号MemWr,值为1表示允许对存储器进行写操作;
(10)读存储器使能信号MemRd,值为1表示允许对存储器进行读操作;
(11)写寄存器值的选择信号[1:
0]MemToReg,选择ALU结果,存储器读取结果和PC+4其中之一作为写入目的寄存器的值;
(12)符号位扩展指示信号EXTOp,值为1表示对16位立即数进行符号位扩展,值为0表示0扩展;
(13)立即数高位取指令指示信号LUOp,值为1表示当前指令为lui指令,选择将立即数载入高16位低位填0的32位立即数作为ALU输入,值为0表示将正常扩展后的32位立即数作为ALU输入;
控制信号的具体产生过程此处略去,在控制信号说明文件中进行详述。
下图为数据通路的总体原理图:
5、寄存器堆模块
寄存器堆模块RegFile根据$Rs,$Rt,$Rd的值和写寄存器使能信号RegWr完成对寄存器堆的读写操作。
6、ALU模块
根据指令内容进行选择后得到两个ALU操作数和ALU运算控制信号ALUFunc及有无符号数指示信号作为ALU输入,完成算术运算、位运算、逻辑运算、移位运算和比较运算,输出为运算结果ALUResult。
7、数据存储器模块
通过读写使能信号、读写地址和写入内容完成对数据存储器的读写操作。
8、外设模块
完成对除UART部分的外设的读写操作,以及实现定时器功能,此模块为实验提供模块。
9、UART模块
此模块通过对串口对应外设地址的读写操作,完成串口收发器的数据接收和数据发送功能。
10、存储器读取结果
读存储器的结果可能是数据存储器或外设中的内容,因此要通过读存储器的地址进行选择,此处该地址即为ALU的计算结果ALUResult(lw指令的读取地址为$Ra寄存器的值加上偏移量),若ALUResult高两位为00表示读取的是数据存储器,若高两位为其它(实际上是01)表示读取的是外设。
若ALUResult[5]为1或ALUResult[4]、[3]为0表示读取UART内容,否则表示读取其他外设的内容。
三、关键代码及文件清单
1、分频模块CPU_clk.v
assignimm16_sll_2bits={{14{imm16[15]}},{imm16,2'
b00}};
assignJT={PC[31:
28],target,2'
b00};
assignILLOP=32'
h80000004;
assignXADR=32'
h80000008;
Adderadd1(.A(PC),.B(4),.CIN(1'
b0),.S(PC_Add_4));
Adderadd2(.A(PC_Add_4),.B({imm16_sll_2bits}),.CIN(1'
b0),.S(ConBA));
always@(posedgeclkornegedgereset)begin
if(!
reset)PC<
=32'
h8000_0000;
elseif(PCSrc==0)PC<
=PC_Add_4;
elseif(PCSrc==1&
&
ALUResult[0]==1'
b0)PC<
elseif(PCSrc==1&
b1)PC<
=ConBA;
elseif(PCSrc==2)PC<
=JT;
elseif(PCSrc==3)PC<
=DataBusA;
elseif(PCSrc==4)PC<
=ILLOP;
elsePC<
=XADR;
end
3、数据通路
ROMIF(.addr(PC),.data(Instruction));
OpcodeToControlcontrol(.OpCode(OpCode),.Funct(Funct),.irq(irq),
.PC31(PC[31]),.IsR(IsR),.PCSrc(PCSrc),.RegDst(RegDst),.RegWr(RegWr),.ALUSrc1(ALUSrc1),.ALUSrc2(ALUSrc2),.ALUFunc(ALUFunc),.Sign(Sign),.MemWr(MemWr),.MemRd(MemRd),.MemToReg(MemToReg),.EXTOp(EXTOp),.LUOp(LUOp));
RegFileRF(.reset(reset),.clk(clk),.addr1(Rs),.data1(DataBusA),.addr2(Rt),
.data2(DataBusB),.wr(RegWr),.addr3(RegWrAddr),.data3(DataBusW));
ALUalu(.SrcA(SrcA),.SrcB(SrcB),.ALUFunc(ALUFunc),.Sign(Sign),
.ALUResult(ALUResult),.Zero(Zero),.OverFlow(OverFlow),.Negative(Negative));
DataMemdm(.reset(reset),.clk(clk),.rd(MemRd),.wr(MemWr),.addr(ALUResult),
.wdata(DataBusB),.rdata(DataMemResult));
Peripheralper(.reset(reset),.clk(clk),.rd(MemRd),.wr(MemWr),.addr(ALUResult),
.wdata(DataBusB),.rdata(PeripheralResult),.led(led),.switch(switch),.digi(digi),.irqout(irq));
UARTuart(.clk(clk),.rd(MemRd),.wr(MemWr),.wdata(DataBusB),.reset(reset),
.DataIn(UARTIn),.addr(ALUResult),.DataOut(UARTOut),.rdata(UARTResult));
assignMemRdData=(ALUResult[31:
30]==2'
b00)DataMemResult:
(ALUResult[5]==1'
b1|(ALUResult[4]&
ALUResult[3]))
UARTResult:
PeripheralResult;
代码文件见附件。
四、仿真结果及分析
第一组输入为00001111(15)和00000101(5),输出为00000101(5);
第二组输入为00000011(3)和00001001(9),输出为00000011(3);
计算结果正确,UART、led、数码管均显示正确。
五、综合情况
六、硬件调试情况
硬件调试工作正常
七、思想体会
在理论课上已经学习过单周期数据通路的搭建,思路比较清晰,老师又对一些关键模块如寄存器堆、存储器、外设等提供了代码,因此,初步搭建一个较为粗糙的单周期数据通路并不困难,然后是结合本次试验的一些要求,逐渐丰富完整数据通路。
比较有难度的是在后续仿真调试过程中遇到的各种复杂情况,需要对硬件作出一些调整,如对存储器的读取,起初并未考虑到数据存储器与外设的区别,因为在理论课中也并未提及到,后来仿真出不了结果,经过反复分析发现是读取存储器的问题,于是针对不同存储地址的区别进行了选择。
从开始着手单周期,包括安排控制信号,到最后仿真出正确结果,综合到开发板上正确显示运行,经历了一个并不容易的过程。
在这个过程中学到了很多东西,也积累了很多经验,很多时候对一个系统来说,开始是非常重要的。
对系统整体有了较为充分的理解,对各部分衔接也有很明确的认识,在思路清晰的情况下搭建一个系统,事半功倍,以后也可以非常方便地修改和调试。
反之,开始的时候很多地方模糊不清,到后面往往越改越糟,即使侥幸成功,也不是高质量的作品。
因此一定开始之前心中一定要想清楚要做什么。
在调试的时候要抓住关键点,出现某个错误,和哪些模块相关,最有可能是什么错误引起的,逐个检查,抓住重点,不慌不乱,错误总是可以检查出来的。
关键还是要有信号,不能觉得错综复杂,看一会儿也看不出原因就想放弃,跟着系统运行一条条指令,一定能找出异常所在。
感谢两位队友非常给力的工作和支持,也感谢老师和助教们提供的帮助。
谢谢。