华中科技大学HUST类MIPS单周期微处理器设计实验报告.docx
《华中科技大学HUST类MIPS单周期微处理器设计实验报告.docx》由会员分享,可在线阅读,更多相关《华中科技大学HUST类MIPS单周期微处理器设计实验报告.docx(29页珍藏版)》请在冰点文库上搜索。
![华中科技大学HUST类MIPS单周期微处理器设计实验报告.docx](https://file1.bingdoc.com/fileroot1/2023-6/17/3f35b567-e4f0-4580-a04b-40ab89431e4c/3f35b567-e4f0-4580-a04b-40ab89431e4c1.gif)
华中科技大学HUST类MIPS单周期微处理器设计实验报告
类MIPS单周期微处理器设计
实验报告
专业:
班级:
学号:
姓名:
一、微处理器各模块设计
各模块的框图结构如上图所示。
由图可知,该处理器包含指令存储器、数据存储器、寄存器组、ALU单元、符号数扩张、控制器、ALU控制译码以及多路复用器等。
图中还忽略了一个单元:
时钟信号产生器,而且以上各个部件必须在时钟信号的控制下协调工作。
1.指令存储器的设计
指令寄存器为ROM类型的存储器,为单一输出指令的存储器。
因此其对外的接口为clk、存储器地址输入信号(指令指针)以及数据输出信号(指令)。
(1)在IPwizard中配置ROM,分配128个字的存储空间,字长为32位宽。
(2)选择输入具有地址寄存功能,只有当时钟上升沿有效时,才进行数据的输出。
(3)配置ROM内存空间的初始化COE文件。
最后单击Generate按钮生成IROM模块。
2.数据存储器的设计
数据存储器为RAM类型的存储器,并且需要独立的读写控制信号。
因此其对外的接口输入信号为clk、we、datain、addr;输出信号为dataout。
数据存储器基本建立过程同ROM的建立。
3.寄存器组设计
寄存器组是指令操作的主要对象,MIPS中一共有32个32位寄存器。
在指令的操作过程中需要区分Rs、Rt、Rd的地址和数据,并且Rd的数据只有在寄存器写信号有效时才能写入,因此该模块的输入为clk、RegWriteAddr、RegWriteData、RegWriteEn、RsAddr、RtAddr、reset;输出信号为RsData、RtData。
由于$0一直输出0,因此当RsAddr、RtAddr为0时,RsData以及RtData必须输出0,否则输出相应地址寄存器的值。
另外,当RegWriteEn有效时,数据应该写入RegWriteAddr寄存器。
并且每次复位时所有寄存器都清零。
代码如下:
moduleregFile(
inputclk,
inputreset,
input[31:
0]regWriteData,
input[4:
0]regWriteAddr,
inputregWriteEn,
output[31:
0]RsData,
output[31:
0]RtData,
input[4:
0]RsAddr,
input[4:
0]RtAddr
);
reg[31:
0]regs[0:
31];
assignRsData=(RsAddr==5'b0)?
32'b0:
regs[RsAddr];
assignRtData=(RtAddr==5'b0)?
32'b0:
regs[RtAddr];
integeri;
always@(posedgeclk)
begin
if(!
reset)
begin
if(regWriteEn==1)
begin
regs[regWriteAddr]=regWriteData;
end
end
else
begin
for(i=0;i<31;i=i+1)
regs[i]=0;
regs[31]=32'hffffffff;
end
end
endmodule
4.ALU设计
在这个简单的MIPS指令集中,微处理器支持add、sub、and、or、slt运算指令,需要利用ALU单元实现运算,同时数据存储指令sw、lw也需要ALU单元计算存储器地址,条件跳转指令beq需要ALU来比较两个寄存器是否相等。
所有这些指令包含的操作为加、减、与、或小于设置5种不同的操作。
该模块根据输入控制信号对输入数据进行相应的操作,并获得输出结果以及零标示,由于MIPS处理器ALU单元利用4根输入控制线的译码决定执行何种操作,因此该模块的接口为:
输入:
input1(32bit),input2(32bit),aluCtr(4bit)
输出:
zero(1bit),alluRes(32bit)
代码如下:
moduleALU(
input[31:
0]input1,
input[31:
0]input2,
input[3:
0]aluCtr,
output[31:
0]aluRes,
outputzero
);
regzero;
reg[31:
0]aluRes;
always@(input1orinput2oraluCtr)
begin
case(aluCtr)
4'b0110:
begin
aluRes=input1-input2;
if(aluRes==0)
zero=1;
else
zero=0;
end
4'b0010:
aluRes=input1+input2;
4'b0000:
aluRes=input1&input2;
4'b0001:
aluRes=input1|input2;
4'b1100:
aluRes=~(input1|input2);
4'b0111:
begin
if(input1aluRes=1;
end
default:
aluRes=0;
endcase
end
endmodule
5.ALU控制设计
ALU单元对应以上5种操作的编码如表所示:
输入信号
操作类型
0000
与
0001
或
0010
加
0110
减
0111
小于设置
通过2位操作类型码以及6位指令功能码就可以产生ALU单元的4位控制信号。
它们之间的对应关系如表所示:
因此该模块的主要功能就是根据译码控制单元产生2位操作码以及6位功能码产生4位ALU控制信号,接口为:
输入:
aluop(2bit),funt(6bit)
输出:
aluctr(4bit)
代码为:
modulealuctr(
input[1:
0]ALUOp,
input[5:
0]funct,
output[3:
0]ALUCtr
);
reg[3:
0]ALUCtr;
always@(ALUOporfunct)
casex({ALUOp,funct})
8'b00xxxxxx:
ALUCtr=4'b0010;
8'b01xxxxxx:
ALUCtr=4'b0110;
8'b11xxxxxx:
ALUCtr=4'b0000;
8'b10xx0000:
ALUCtr=4'b0010;
8'b10xx0010:
ALUCtr=4'b0110;
8'b10xx0100:
ALUCtr=4'b0000;
8'b10xx0101:
ALUCtr=4'b0001;
8'b10xx1010:
ALUCtr=4'b0111;
endcase
endmodule
6.控制器设计
控制器输入为指令的opCode字段,即操作码。
操作码经过主控制单元的译码,给ALUCtr、Data、Memory、Registers、Muxs等部件输出正的控制信号。
微处理器在执行不同指令时,控制信号相对应的状态表如下:
因此该模块的接口为:
输入:
opcode(6bit)
输出:
alusrc,memtoreg,regwrite,memread,memwrite,branch,,aluop[1:
0],jmp
代码为:
modulectr(
input[5:
0]opCode,
outputregDst,
outputaluSrc,
outputmemToReg,
outputregWrite,
outputmemRead,
outputmemWrite,
outputbranch,
output[1:
0]aluop,
outputjmp
);
regregDst;
regaluSrc;
regmemToReg;
regregWrite;
regmemRead;
regmemWrite;
regbranch;
reg[1:
0]aluop;
regjmp;
always@(opCode)
begin
case(opCode)
6'b000010:
//jmp
begin
regDst=0;
aluSrc=0;
memToReg=0;
regWrite=0;
memRead=0;
memWrite=0;
branch=0;
aluop=2'b00;
jmp=1;
end
6'b000000:
//R
begin
regDst=1;
aluSrc=0;
memToReg=0;
regWrite=1;
memRead=0;
memWrite=0;
branch=0;
aluop=2'b10;
jmp=0;
end
6'b100011:
//lw
begin
regDst=0;
aluSrc=1;
memToReg=1;
regWrite=1;
memRead=1;
memWrite=0;
branch=0;
aluop=2'b00;
jmp=0;
end
6'b101011:
//sw
begin
regDst=0;
aluSrc=1;
memToReg=0;
regWrite=0;
memRead=0;
memWrite=1;
branch=0;
aluop=2'b00;
jmp=0;
end
6'b000100:
//beq
begin
regDst=0;
aluSrc=0;
memToReg=0;
regWrite=0;
memRead=0;
memWrite=0;
branch=1;
aluop=2'b01;
jmp=0;
end
6'b001100:
//andi
begin
regDst=0;
aluSrc=1;
memToReg=0;
regWrite=1;
memRead=0;
memWrite=0;
branch=0;
aluop=2'b11;
jmp=0;
end
default:
begin
regDst=0;
aluSrc=0;
memToReg=0;
regWrite=0;
memRead=0;
memWrite=0;
branch=0;
aluop=2'b00;
jmp=0;
end
endcase
end
endmodule
7.符号数扩展
将16位有符号扩展为32位有符号数。
带符号扩展只需要在前面补足符号即可。
代码为:
modulesignext(
input[15:
0]inst,
output[31:
0]data
);
assigndata=inst[15:
15]?
{16'hffff,inst}:
{16'h0000,inst};
endmodule
8.顶层模块
顶层模块需要将前面多个模块实例化,通过导线以及多路复用器将各个部件连接起来,并且在时钟的控制下修改PC的值,PC是一个32位的寄存器,每个时钟沿自动增加4。
多路复用器MUX直接通过三目运算符实现:
AssignOUT=SEL?
INPUT1:
INPUT2;
其中,OUT、SEL、INPUT1、INPUT2都是预先定义的信号。
代码如下:
moduletop(
inputclkin,
inputreset
);
reg[31:
0]pc,add4;
wirechoose4;
wire[31:
0]expand2,mux2,mux3,mux4,mux5,address,jmpaddr,inst;
wire[4:
0]mux1;
//wireforcontroller
wirereg_dst,jmp,branch,memread,memwrite,memtoreg;
wire[1:
0]aluop;
wirealu_src,regwrite;
//wireforaluunit
wirezero;
wire[31:
0]aluRes;
//wireforaluctr
wire[3:
0]aluCtr;
//wireformemory
wire[31:
0]memreaddata;
//wireforregister
wire[31:
0]RsData,RtData;
//wireforext
wire[31:
0]expand;
always@(negedgeclkin)
begin
if(!
reset)begin
pc=mux5;
add4=pc+4;
end
elsebegin
pc=32'b0;
add4=32'h4;
end
end
ctrmainctr(
.opCode(inst[31:
26]),
.regDst(reg_dst),
.aluSrc(alu_scr),
.memToReg(memtoreg),
.regWrite(regwrite),
.memRead(memread),
.memWrite(memwrite),
.branch(branch),
.aluop(aluop),
.jmp(jmp));
ALUalu(.input1(RsData),
.input2(mux2),
.aluCtr(aluCtr),
.zero(zero),
.aluRes(aluRes));
aluctraluctr1(.ALUOp(aluop),
.funct(inst[5:
0]),
.ALUCtr(aluCtr));
dramdmem(
.a(aluRes[7:
2]),
.d(RtData),
.clk(!
clkin),
.we(memwrite),
.spo(memreaddata)
);
irom_numberimem(
.a(pc[8:
2]),
.clk(clkin),
.spo(inst)
);
regFileregfile(
.RsAddr(inst[25:
21]),
.RtAddr(inst[20:
16]),
.clk(!
clkin),
.reset(reset),
.regWriteAddr(mux1),
.regWriteData(mux3),
.regWriteEn(regwrite),
.RsData(RsData),
.RtData(RtData)
);
signextsignext(.inst(inst[15:
0]),.data(expand));
assignmux1=reg_dst?
inst[15:
11]:
inst[20:
16];
assignmux2=alu_scr?
expand:
RtData;
assignmux3=memtoreg?
memreaddata:
aluRes;
assignmux4=choose4?
address:
add4;
assignmux5=jmp?
jmpaddr:
mux4;
assignchoose4=branch&zero;
assignexpand2=expand<<2;
assignjmpaddr={add4[31:
28],inst[25:
0],2'b00};
assignaddress=pc+expand2;
endmodule
二、Rom汇编程序设计
下面以将本人学号U201513343的ASCII码存入RAM的连续内存区域编写为汇编程序为例:
编辑MIPS汇编源代码:
采用ultraedit编辑汇编源程序代码,并保存为number.asm文件。
代码如下:
main:
andi$2,$31,85#U
sw$2,0($3)
andi$2,$31,50#2
sw$2,4($3)
andi$2,$31,48#0
sw$2,8($3)
andi$2,$31,49#1
sw$2,12($3)
andi$2,$31,53#5
sw$2,16($3)
andi$2,$31,49#1
sw$2,20($3)
andi$2,$31,51#3
sw$2,24($3)
andi$2,$31,51#3
sw$2,28($3)
andi$2,$31,52#4
sw$2,32($3)
andi$2,$31,51#3
sw$2,36($3)
jmain
获取机器代码,并保存为coe文件:
利用QtSpim装载number.asm,并测试功能是否正常。
装载之后的用户代码段在QtSpim中的结构如附图所示:
提取的用户代码对应的机器码,并把jmain指令对应的机器码0x08100009修改为0x08000000。
将上述机器指令保存在ultraedit中新的文件中,添加coe文件头描述语句,完成后的完整coe文件内容如下:
MEMORY_INITIALIZATION_RADIX=16;
MEMORY_INITIALIZATION_VECTOR=
33e20055,
ac620000,
33e20032,
ac620004,
33e20030,
ac620008,
33e20031,
ac62000c,
33e20035,
ac620010,
33e20031,
ac620014,
33e20033,
ac620018,
33e20033,
ac62001c,
33e20034,
ac620020,
33e20033,
ac620024,
08000000,
将该文件保存为coe文件,即number.coe。
至此,coe文件制作完成。
最后,把coe文件导入irom中,如下图所示:
三、模块仿真
1.寄存器组仿真:
建立仿真代码,在自动生成的激励代码基础上加入功能仿真需要的代码:
reset测试、写入测试、输出测试等、完整代码如下:
moduleregsim;
//Inputs
regclk;
regreset;
reg[31:
0]regWriteData;
reg[4:
0]regWriteAddr;
regregWriteEn;
reg[4:
0]RsAddr;
reg[4:
0]RtAddr;
//Outputs
wire[31:
0]RsData;
wire[31:
0]RtData;
//InstantiatetheUnitUnderTest(UUT)
regFileuut(
.clk(clk),
.reset(reset),
.regWriteData(regWriteData),
.regWriteAddr(regWriteAddr),
.regWriteEn(regWriteEn),
.RsData(RsData),
.RtData(RtData),
.RsAddr(RsAddr),
.RtAddr(RtAddr)
);
integeri;
initialbegin
//InitializeInputs
clk=0;
reset=0;
regWriteData=0;
regWriteAddr=0;
regWriteEn=0;
RsAddr=0;
RtAddr=0;
//Wait100nsforglobalresettofinish
#100;
//Addstimulushere
regWriteData=32'h55aaaa55;
regWriteEn=1;
reset=1;
#100;
reset=0;
end
parameterPERIOD=20;
alwaysbegin
clk=1'b0;
#(PERIOD/2)clk=1'b1;
#(PERIOD/2);
end
alwaysbegin
for(i=31;i>=1;i=i-1)begin
regWriteAddr=i;
RsAddr=i;
#PERIOD;
end
end
endmodule
仿真结果如下:
下图可以观察到Reset为高电平状态。
Reset高电平状态下输出数据为0,表示Reset有效地工作了。
Reset信号无效后,正常输入和输出数据。
第一次for循环的地址范围输出数据在时钟低电平时输出0,高电平输出0x55aaaa55,如下图所示,表明数据正确地在时钟上升沿写入的。
之后一直输出的数据与写入的数据相同,表明数据都正确地保存在寄存器组中。
2.控制器仿真:
控制器仿真需要包含所有case的输入,仿真激励文件修改代码后,如下:
modulectrsim;
//Inputs
reg[5:
0]opCode;
//Outputs
wireregDst;
wirealuSrc;
wirememToReg;
wireregWrite;
wirememRead;
wirememWrite;
wirebranch;
wire[1:
0]aluop;
wirejmp;
//InstantiatetheUnitUnderTest(UUT)
ctruut(
.opCode(opCode),
.regDst(regDst),
.aluSrc(aluSrc),
.memToReg(memToReg),
.regWrite(regWrite),
.memRead(memRead),
.memWrite(memWrite),
.branch(branch),
.aluop(aluop),
.jmp(jmp)
);
initialbegin
//InitializeInputs
opCode=0;
//Wait100nsforglobalresettofinish
#100;
opCode=6'b000010;//jump
#100;
opCode=6'b000000;//R
#100;
opCode=6'b100011;//lw
#100;
opCode