系统硬件综合设计-多周期CPU的设计与实现
目录1 实验目的和要求1 实验目的和要求基于先修课程,根据系统设计思想,使用硬件描述语言设计实现一款兼容MIPS32指令集子集的处理器(CPU),完成单周期CPU设计,或多周期CPU设计,或5级流水线CPU设计(递进式、难度依次提升。必须至少完成单周期CPU的设计工作),并将设计的CPU,下载至FPGA开发板上运行。以此贯穿数字逻辑、计算机组成原理、计算机体系结构课程,实现从逻辑门至完整CPU处理
计算机组成原理 实验五 单周期CPU设计与实现——十条指令CPU
目录
1 实验目的和要求
基于先修课程,根据系统设计思想,使用硬件描述语言设计实现一款兼容MIPS32指令集子集的处理器(CPU),完成单周期CPU设计,或多周期CPU设计,或5级流水线CPU设计(递进式、难度依次提升。必须至少完成单周期CPU的设计工作),并将设计的CPU,下载至FPGA开发板上运行。以此贯穿数字逻辑、计算机组成原理、计算机体系结构课程,实现从逻辑门至完整CPU处理器的设计。
1.1 实验目的
- 认识和掌握多周期数据通路原理及其设计方法;
- 掌握多周期CPU的实现方法,代码实现方法;
- 编写一个编译器,将MIPS汇编程序编译为二进制机器码;
- 掌握多周期CPU的测试方法;
- 掌握多周期CPU的实现方法。
1.2 实验要求
设计一个多周期CPU,该CPU能实现以下指令功能操作。设计的指令与格式如下:
算术运算指令:
(1)add rd, rs, rt
000000 rs(5位) rt(5位) rd(5位) reserved
功能:rd<-rs + rt
(2)sub rd, rs, rt
000001 rs(5位) rt(5位) rd(5位) reserved
功能:rd<-rs - rt
(3)addi rt, rs, immediate
000010 rs(5位) rt(5位) immediate(16位)
功能:rt<-rs + (sign-extend)immediate
逻辑运算指令:
(4)or rd, rs, rt
010000 rs(5位) rt(5位) rd(5位) reserved
功能:rd<-rs | rt
(5)and rd, rs, rt
010001 rs(5位) rt(5位) rd(5位) reserved
功能:rd<-rs & rt
(6)ori rt, rs, immediate
010010 rs(5位) rt(5位) immediate
功能:rt<-rs | (zero-extend)immediate
移位指令:
(7)sll rd, rt,sa
011000 未用 rt(5位) rd(5位) sa reserved
功能:rd<-rt<<(zero-extend)sa,左移sa位 ,(zero-extend)sa
比较指令:
(8) slt rd, rs, rt 带符号数
100110 rs(5位) rt(5位) rd(5位) reserved
功能:if (rs<rt) rd =1 else rd=0
(9) sltiu rt, rs,immediate 不带符号
100111 rs(5位) rt(5位) immediate(16位)
功能:if (rs <(zero-extend)immediate) rt =1 else rt=0
存储器读写指令:
(10)sw rt, immediate(rs)
110000 rs(5位) rt(5位) immediate(16位)
功能:memory[rs+ (sign-extend)immediate]<-rt。即将rt寄存器的内容保存到r寄存器内容和立即数符号扩展后的数相加作为地址的内存单元中。
(11)lw rt, immediate(rs)
110001 rs(5位) rt(5位) immediate(16位)
功能:rt <- memory[rs +(sign-extend)immediate]。即读取rs寄存器内容和立即数符号扩展后的数相加作为地址的内存单元中的数,然后保存到rt寄存器中。
分支指令:
(12)beq rs,rt, immediate
110100 rs(5位) rt(5位) immediate(16位)
功能:if(rs=rt) pc <-pc + 4 + (sign-extend)immediate <<2 else pc <-pc + 4
(13)bltz rs,immediate
110110 rs(5位) 00000 immediate
功能:if(rs<0) pc←pc + 4 + (sign-extend)immediate <<2 else pc ←pc + 4
跳转指令:
(14)j addr
111000 addr[27:2]
功能:pc <-{(pc+4)[31:28],addr[27:2],2’b00},跳转。
(15)jr rs
111001 rs(5位) 未用 未用 reserved
功能:pc <- rs,跳转。
调用子程序指令:
(16)jal addr
111010 addr[27:2]
功能:调用子程序,pc <- {(pc+4)[31:28],addr[27:2],2’b00};$31<-pc+4,返回地址设置;子程序返回,需用指令 jr $31。跳转地址的形成同 j addr 指令。
停机指令:
(17)halt (停机指令)
111111 00000000000000000000000000(26位)
不改变pc的值,pc保持不变。
2 实验内容
2.1 多周期CPU设计
CPU在处理指令时,一般需要经过以下几个阶段:
(1) 取指令(IF):根据程序计数器pc中的指令地址,从存储器中取出一条指令,同时,pc根据指令字长度自动递增产生下一条指令所需要的指令地址,但遇到“地址转移”指令时,则控制器把“转移地址”送入pc,当然得到的“地址”需要做些变换才送入pc。
(2) 指令译码(ID):对取指令操作中得到的指令进行分析并译码,确定这条指令需要完成的操作,从而产生相应的操作控制信号,用于驱动执行状态中的各种操作。
(3) 指令执行(EXE):根据指令译码得到的操作控制信号,具体地执行指令动作,然后转移到结果写回状态。
(4) 存储器访问(MEM):所有需要访问存储器的操作都将在这个步骤中执行,该步骤给出存储器的数据地址,把数据写入到存储器中数据地址所指定的存储单元或者从存储器中得到数据地址单元中的数据。
(5) 结果写回(WB):指令执行的结果或者访问存储器中得到的数据写回相应的目的寄存器中。
本次实验中就按照这五个阶段进行设计,这样一条指令的执行最长需要五个(小)时钟周期才能完成。具体指令所需的时钟周期需要根据实际情况而定,这便是多周期CPU。
多周期CPU指令处理过程:
MIPS指令的三种格式:
op:为操作码; rs:为第1个源操作数寄存器,寄存器地址(编号)是00000~ 11111,00~1F;
rt:为第2个源操作数寄存器,或目的操作数寄存器,寄存器地址(同上); rd:为目的操作数寄存器,寄存器地址(同上);
sa:为位移量(shift amt),移位指令用于指定移多少位; funct:为功能码,在寄存器类型指令中(R类型)用来指定指令的功能;
immediate:为16位立即数,用作无符号的逻辑操作数、有符号的算术操作数、数据加载(Load)/数据保存(Store)指令的数据地址字节偏移量和分支指令中相对程序计数器(PC)的有符号偏移量;
address:为地址。
多周期CPU状态转移图
状态的转移有的是无条件的,例如从sIF状态转移到sID就是无条件的;有些是有条件的,例如sEXE状态之后不止一个状态,到底转向哪个状态由该指令功能,即指令操作码决定。每个状态代表一个时钟周期。
控制信号作用表:
相关部件及引脚说明: Instruction Memory:指令存储器 Iaddr,指令地址输入端口
DataIn,存储器数据输入端口 DataOut,存储器数据输出端口 RW,指令存储器读写控制信号,为0写,为1读 Data
Memory:数据存储器 Daddr,数据地址输入端口 DataIn,存储器数据输入端口 DataOut,存储器数据输出端口
/RD,数据存储器读控制信号,为0读 /WR,数据存储器写控制信号,为0写 Register File:寄存器组 Read
Reg1,rs寄存器地址输入端口 Read Reg2,rt寄存器地址输入端口 Write
Reg,将数据写入的寄存器,其地址输入端口(rt、rd) Write Data,写入寄存器的数据输入端口 Read
Data1,rs寄存器数据输出端口 Read Data2,rt寄存器数据输出端口 WE,写使能信号,为1时,在时钟边沿触发写入
IR: 指令寄存器,用于存放正在执行的指令代码 ALU: 算术逻辑单元 result,ALU运算结果
zero,运算结果标志,结果为0,则zero=1;否则zero=0
sign,运算结果标志,结果最高位为0,则sign=0,正数;否则,sign=1,负数
2.2 多周期CPU实现
多周期CPU模块划分图
本实验将CPU划分为14个模块。将一些数据选择的模块并入到其所需要的功能模块中,没有完全依据多周期CPU数据通路图进行划分,否则需要过多模块,划分的太过冗余。
3 模块功能及核心代码:
1. pcAdd
模块功能:根据控制信号PCSrc,计算获得下一个pc以及控制信号Reset重置。
核心代码:
always@(*)
begin
if(!RST) begin
nextPC = 0;
end
else begin
pc = curPC + 4;
case(PCSrc)
2'b00: nextPC = curPC + 4;
2'b01: nextPC = curPC + 4 + immediate * 4;
2'b10: nextPC = rs;
2'b11: nextPC = {pc[31:28],addr,2'b00};
endcase
end
2. PC
模块功能:根据控制信号PCWre,判断pc是否改变以及根据Reset信号判断是否重置。
核心代码:
always@(posedge CLK or negedge RST)
begin
if(!RST) // Reset == 0, PC = 0
begin
curPC <= 0;
end
else
begin
if(PCWre) // PCWre == 1
begin
curPC <= nextPC;
end
else // PCWre == 0, halt
begin
curPC <= curPC;
end
end
end
3. InsMEM
模块功能:依据当前pc和信号量InsMemRW,读取指令寄存器中,相对应地址的指令。
核心代码:
initial
begin//加载数据到存储器ROM
$readmemh("D:\\Modelsim\\examples\\CPU2.0\\romdata.txt", rom);
end
always@(IAddr or InsMemRW)//敏感信号
begin
if(InsMemRW)
begin//大端
IDataOut[7:0] = rom[IAddr + 3];
IDataOut[15:8] = rom[IAddr + 2];
IDataOut[23:16] = rom[IAddr + 1];
IDataOut[31:24] = rom[IAddr];
end
end
4. IR
模块功能:为了使指令代码保持稳定。
核心代码:
initial begin
IRInstruction = 0;
end
always@(posedge CLK)//上升沿
begin
if(IRWre) begin
IRInstruction <= instruction;
end
end
5. InstructionCut
模块功能:对指令进行分割,获得相对应的指令信息。
核心代码:
always@(instruction)
begin
op = instruction[31:26];
rs = instruction[25:21];
rt = instruction[20:16];
rd = instruction[15:11];
sa = instruction[10:6];
immediate = instruction[15:0];
addr = instruction[25:0];
end
6. ControlUnit
模块功能:控制单元,依据指令的操作码(op)、标记符(ZERO)以及当前CPU状态,依据表三
控制信号、指令以及执行状态之间的相互关系,输出相匹配控制信号量。
核心代码:
reg [2:0] state, nextState;
parameter [2:0] iniState = 3'b111,
sIF = 3'b000,
sID = 3'b001,
sEXE = 3'b010,
sMEM = 3'b100,
sWB = 3'b011;
initial begin
state = iniState;
PCWre = 0;
InsMemRW = 0;
IRWre = 0;
RegWre = 0;
ExtSel = 0;
PCSrc = 2'b00;
RegDst = 2'b11;
ALUOp = 0;
ExtSel = 0;
WrRegDSrc = 0;
ALUSrcA = 0;
ALUSrcB = 0;
DBDataSrc = 0;
mRD = 0;
mWR = 0;
end
always@(posedge CLK) begin
if(!RST) begin
state <= sIF;
end else begin
state <= nextState;
end
end
always@(state or op or zero) begin
//
case(state)
iniState : nextState = sIF;
sIF: nextState = sID;
sID: begin
case(op[5:3])
3'b111: nextState = sIF; //
default: nextState = sEXE;
endcase
end
sEXE: begin
if((op == 6'b110100) || (op == 6'b110110)) begin
//beq,bltz
nextState = sIF;
end else if(op == 6'b110000 || op == 6'b110001) begin
//sw,lw
nextState = sMEM;
end else begin
nextState = sWB;
end
end
sMEM: begin
if(op == 6'b110000) begin
//sw
nextState = sIF;
end else begin
//lw
nextState = sWB;
end
end
sWB: nextState = sIF;
endcase
// PCWre and InsMemRW
if(nextState == sIF && op != 6'b111111 && state != iniState) begin
// halt
PCWre = 1;
InsMemRW = 1;
end else begin
PCWre = 0;
InsMemRW = 0;
end
// IRWre
if(state == sIF || nextState == sID) begin
IRWre = 1;
end else begin
IRWre = 0;
end
// ALUSrcA
if(op == 6'b011000) begin
// sll
ALUSrcA = 1;
end else begin
ALUSrcA = 0;
end
// ALUSrcB
if(op == 6'b000010 || op == 6'b010010 || op == 6'b110000 || op == 6'b110001 || op == 6'b100111) begin
// addi,ori,sw,lw,sltiu
ALUSrcB = 1;
end else begin
ALUSrcB = 0;
end
// DBDataSrc
if(op == 6'b110001) begin
// lw
DBDataSrc = 1;
end else begin
DBDataSrc = 0;
end
// RegWre and WrRegDSrc and RegDst
if((state == sWB && op != 6'b110100 && op != 6'b110000 && op != 6'b110110) || (op == 6'b111010 && state == sID)) begin
RegWre = 1;
if(op == 6'b111010) begin
// jal
WrRegDSrc = 0;
RegDst = 2'b00;
end else begin
WrRegDSrc = 1;
if(op == 6'b000010 || op == 6'b010010 || op == 6'b100111 || op == 6'b110001) begin
// addi, ori, sltiu, lw
RegDst = 2'b01;
end else begin
// add, sub, or, and, slt, sll
RegDst = 2'b10;
end
end
end else begin
RegWre = 0;
end
// InsMemRW
if(op != 6'b111111)
InsMemRW = 1;
// mRD
mRD = (op == 6'b110001) ? 1 : 0; // lw
// mWR
mWR = (state == sMEM && op == 6'b110000) ? 1 : 0; // sw
// ExtSel
ExtSel = (op == 6'b000010 || op == 6'b110001 || op == 6'b110000 || op == 6'b110100 || op == 6'b110110) ? 1 : 0; // addi?lw?sw?beq?bltz
// PCSrc
if(op == 6'b111001) begin
// jr
PCSrc = 2'b10;
end else if((op == 6'b110100 && zero) || (op == 6'b110110 && !zero)) begin
// beq ? bltz??
PCSrc = 2'b01;
end else if(op == 6'b111010 || op == 6'b111000) begin
// j,jal
PCSrc = 2'b11;
end else begin
PCSrc = 2'b00;
end
// ALUOp
case(op)
6'b000010: ALUOp = 3'b000; // addi
6'b010010: ALUOp = 3'b101; // ori
6'b010000: ALUOp = 3'b101; // or
6'b000001: ALUOp = 3'b001; // sub
6'b010001: ALUOp = 3'b110; // and
6'b011000: ALUOp = 3'b100; // sll
6'b110100: ALUOp = 3'b001; // beq
6'b100110: ALUOp = 3'b011; // slt
6'b100111: ALUOp = 3'b010; // sltiu
6'b110110: ALUOp = 3'b001; // bltz
6'b110001: ALUOp = 3'b000; //sw
6'b110000: ALUOp = 3'b000; //lw
endcase
end
7. RegisterFile
模块功能:寄存器组,通过控制单元输出的控制信号,进行相对应的读或写操作。
核心代码:
reg [31:0] regFile[0:31]; // ????????reg??
integer i;
initial begin
for (i = 0; i < 32; i = i+ 1) regFile[i] <= 0;
end
always@(ReadReg1 or ReadReg2)
begin
ReadData1 = regFile[ReadReg1];
ReadData2 = regFile[ReadReg2];
//$display("regfile %d %d\n", ReadReg1, ReadReg2);
end
always@(negedge CLK)
begin
//$0??0??????????????0
if(RegWre && WriteReg)
begin
regFile[WriteReg] <= WriteData;
end
end
always@(*)
begin
case(RegDst)
2'b00: WriteReg = 31;
2'b01: WriteReg = ReadReg2;
2'b10: WriteReg = rd;
endcase
end
8. SignZeroExtend
模块功能:根据指令相关的控制信号ExtSel,对立即数进行扩展。
核心代码:
assign extendImmediate[15:0] = immediate;
assign extendImmediate[31:16] = ExtSel ? (immediate[15] ? 16'hffff : 16'h0000) : 16'h0000;
9. ALU
模块功能:算术逻辑单元,对两个输入依据ALUOp进行相对应的运算。
核心代码:
reg [31:0] A;
reg [31:0] B;
initial begin
result = 0;
zero = 0;
end
always@(ReadData1 or ReadData2 or ALUSrcA or ALUSrcB or ALUOp)
begin
A = (ALUSrcA == 0) ? ReadData1 : sa;
B = (ALUSrcB == 0) ? ReadData2 : extend;
case(ALUOp)
3'b000: result = A + B;
3'b001: result = A - B;
3'b010: result = (A < B) ? 1 : 0;
3'b011: result = (((ReadData1 < ReadData2) && (ReadData1[31] == ReadData2[31] )) ||( ( ReadData1[31] ==1 && ReadData2[31] == 0))) ? 1:0;
3'b100: result = B << A;
3'b101: result = A | B;
3'b110: result = A & B;
3'b111: result = A ^ B;
endcase
zero = (result == 0) ? 1 : 0;
end
10. DataMEM
模块功能:数据存储器,通过控制信号,对数据寄存器进行读或者写操作,并且此处模块额外合并了输出DB的数据选择器,此模块同时输出写回寄存器组的数据DB。
核心代码:
initial begin
DB <= 16'b0;
end
reg [7:0] ram [0:31]; //
always@(mRD or DAddr or DBDataSrc)
begin
//
DataOut[7:0] = mRD ? ram[DAddr + 3] : 8'bz; //
DataOut[15:8] = mRD ? ram[DAddr + 2] : 8'bz;
DataOut[23:16] = mRD ? ram[DAddr + 1] : 8'bz;
DataOut[31:24] = mRD ? ram[DAddr] : 8'bz;
DB = (DBDataSrc == 0) ? DAddr : DataOut;
end
always@(mWR or DAddr)
begin
//
if(mWR)
begin
ram[DAddr] = DataIn[31:24];
ram[DAddr + 1] = DataIn[23:16];
ram[DAddr + 2] = DataIn[15:8];
ram[DAddr + 3] = DataIn[7:0];
end
end
11. 寄存器ADR、BDR、ALUoutDR、DBDR
模块功能:切分数据通路,将大组合逻辑切分为若干个小组合逻辑,大延迟变为多个分段小延迟。
核心代码:
module TempReg(
input CLK,
input [31:0] IData,
output reg[31:0] OData
);
initial begin
OData = 0;
end
always@(posedge CLK) begin
OData <= IData;
end
endmodule
12. 顶层模块:MultiCycleCPU
模块功能:在顶层模块中将各个已实现的底层模块进行实列,并且用verilog语言将各个模块用线连接起来。
ControlUnit ControlUnit(.CLK(CLK),
.RST(RST),
.zero(zero),
.op(op),
.IRWre(IRWre),
.PCWre(PCWre),
.ExtSel(ExtSel),
.InsMemRW(InsMemRW),
.WrRegDSrc(WrRegDSrc),
.RegDst(RegDst),
.RegWre(RegWre),
.ALUSrcA(ALUSrcA),
.ALUSrcB(ALUSrcB),
.PCSrc(PCSrc),
.ALUOp(ALUOp),
.mRD(mRD),
.mWR(mWR),
.DBDataSrc(DBDataSrc));
pcAdd pcAdd(.RST(RST),
.PCSrc(PCSrc),
.immediate(extend),
.addr(addr),
.curPC(curPC),
.rs(A),
.nextPC(nextPC));
PC PC(.CLK(CLK),
.RST(RST),
.PCWre(PCWre),
.nextPC(nextPC),
.curPC(curPC));
InsMEM InsMEM(.IAddr(curPC),
.InsMemRW(InsMemRW),
.IDataOut(instruction));
IR IR(.instruction(instruction),
.CLK(CLK),
.IRWre(IRWre),
.IRInstruction(IRInstruction));
InstructionCut InstructionCut(.instruction(IRInstruction),
.op(op),
.rs(rs),
.rt(rt),
.rd(rd),
.sa(sa),
.immediate(immediate),
.addr(addr));
SignZeroExtend SignZeroExtend(.immediate(immediate),
.ExtSel(ExtSel),
.extendImmediate(extend));
RegisterFile RegisterFile(.CLK(CLK),
.ReadReg1(rs),
.ReadReg2(rt),
.rd(rd),
.WriteData(WrRegDSrc ? dataDB : curPC + 4),
.RegDst(RegDst),
.RegWre(RegWre),
.ReadData1(A),
.ReadData2(B),
.WriteReg(WriteReg));
TempReg ADR(.CLK(CLK),
.IData(A),
.OData(dataA));
TempReg BDR(.CLK(CLK),
.IData(B),
.OData(dataB));
ALU alu(.ALUSrcA(ALUSrcA),
.ALUSrcB(ALUSrcB),
.ReadData1(dataA),
.ReadData2(dataB),
.sa(sa),
.extend(extend),
.ALUOp(ALUOp),
.zero(zero),
.result(result));
TempReg ALUoutDR(.CLK(CLK),
.IData(result),
.OData(dataResult));
DataMEM DataMEM(.mRD(mRD),
.mWR(mWR),
.DBDataSrc(DBDataSrc),
.DAddr(result),
.DataIn(dataB),
.DataOut(DataOut),
.DB(DB));
TempReg DBDR(.CLK(CLK),
.IData(DB),
.OData(dataDB));
4 实验结果与分析
测试程序段:
将指令代码初直接写入始化到指令存储器中。初始化PC的值,也就是以上程序段首地址PC=0x00000000,以上程序段从0x00000000地址开始存放。运行ModelSim进行仿真,看波形。使用表3进行测试CPU正确性,将其中的指令写入一个文件romData.txt。在模块InsMEM中进行读入。
initial
begin//加载数据到存储器ROM
$readmemh("D:\\Modelsim\\examples\\CPU2.0\\romdata.txt", rom);
End
分析:加法操作指令,将0号寄存器的数据(0)与立即数8相加,并且将运算结果(8)写回1号寄存器。需要取指令,指令译码,指令执行,结果写回四个步骤,不需要存储器访问,因此四个周期即可完成,在最后一个时钟周期的下降沿写入数据。
分析:或操作指令,将0号寄存器的数据(0)与立即数2进行或操作,并且将运算结果(2)写回2号寄存器。需要取指令,指令译码,指令执行,结果写回四个步骤,不需要存储器访问,因此四个周期即可完成,在最后一个时钟周期的下降沿写入数据。
分析:或操作指令,将2号寄存器的数据(2)与1号寄存器的数据(8)进行或操作,并且将运算结果(10)写回3号寄存器。需要取指令,指令译码,指令执行,结果写回四个步骤,不需要存储器访问,因此四个周期即可完成,在最后一个时钟周期的下降沿写入数据。
分析:减操作指令,将3号寄存器的数据(10)与1号寄存器的数据(8)进行减操作,并且将运算结果(2)写回4号寄存器。需要取指令,指令译码,指令执行,结果写回四个步骤,不需要存储器访问,因此四个周期即可完成,在最后一个时钟周期的下降沿写入数据。
分析:与操作指令,将4号寄存器的数据(2)与2号寄存器的数据(2)进行与操作,并且将运算结果(2)写回5号寄存器。需要取指令,指令译码,指令执行,结果写回四个步骤,不需要存储器访问,因此四个周期即可完成,在最后一个时钟周期的下降沿写入数据。
分析:移位操作指令,将5号寄存器的数据(2)左移2位,并且将运算结果(8)写回5号寄存器。需要取指令,指令译码,指令执行,结果写回四个步骤,不需要存储器访问,因此四个周期即可完成,在最后一个时钟周期的下降沿写入数据。
分析:分支指令,将5号寄存器的数据(8)与1号寄存器的数据(8)进行比较,如果二者相等则跳转,跳转然后执行上一条指令(地址:0x00000014),否则继续顺序执行。本条指令将发生跳转,因为$5与$1所存储的数据相等。因此5号寄存器的数据(8)将左移2位,并且将运算结果(32)写回5号寄存器。需要取指令,指令译码,指令执行,结果写回四个步骤,不需要存储器访问,因此四个周期即可完成,在最后一个时钟周期的下降沿写入数据。
分析:调用子程序指令,调用指令寄存器中地址0x00000040所存储的指令,同时将寄存器组中的31号寄存器存储当前PC+4的值(0x00000020)。指令需要取指令、指令译码两个步骤,不需要指令执行、存储器访问和数据写回,因此两个周期即可完成。
分析:比较指令,将$12寄存器的数据(2)与$1寄存器的数据(8)比较,若$12的数据小于$1寄存器的数据,则将1写入$8,否则写入0,本指令将1写入$8。不需要存储器访问,因此四个周期即可完成,在最后一个时钟周期的下降沿写入数据。
分析:加操作指令,将$0寄存器的数据(0)与立即数(-2)相加,将结果(-2)写入$13,。指令需要取指令、指令译码、指令执行和数据写回四个步骤,不需要存储器访问,因此四个周期即可完成,在最后一个时钟周期的下降沿写入数据。
分析:比较指令,将$8寄存器的数据(1)与$13寄存器的数据(-2)比较,若$8的数据小于$13寄存器的数据,则将1写入$9,否则写入0,本指令将0写入$9。不需要存储器访问,因此四个周期即可完成,在最后一个时钟周期的下降沿写入数据。
分析:比较指令,将$9寄存器的数据(0)与立即数(2)比较,若$9的数据小于2,则将1写入$10,否则写入0,本指令将1写入$10。不需要存储器访问,因此四个周期即可完成,在最后一个时钟周期的下降沿写入数据。
分析:比较指令,将$10寄存器的数据(1)与立即数(0)比较,若$10的数据小于0,则将1写入$10,否则写入0,本指令将0写入$11。不需要存储器访问,因此四个周期即可完成,在最后一个时钟周期的下降沿写入数据。
分析:加操作指令,将$13寄存器的数据(-2)与立即数(1)相加,将结果(-1)写入$13,。指令需要取指令、指令译码、指令执行和数据写回四个步骤,不需要存储器访问,因此四个周期即可完成,在最后一个时钟周期的下降沿写入数据。
分析:分支指令,将13号寄存器的数据(-1)与0进行比较,如果小于则跳转,跳转然后执行上一条指令(地址:0x00000034),否则继续顺序执行。本条指令将发生跳转,因为$13所存储的数据(-1)小于0。因此$13的数据将(-1)加1,并且将运算结果(0)写回寄存器$13。不需要存储器访问,因此四个周期即可完成,在最后一个时钟周期的下降沿写入数据。
分析:跳转指令,跳转到地址0x0000004C。指令需要取指令和指令译码,不需要指令执行、存储器访问和数据写回,因此两个周期即可完成。
分析:停机指令,即PC将不再改变。
5 项目文件
百度网盘:
链接:https://pan.baidu.com/s/1-rBp2vUFfPayk6L_MKL_FA
提取码:7u8q
InsMEM.v文件中需要自己更改绝对路径
6 后记
既来之 则赞之
若有疑问,欢迎评论
本文仅供参考,务必独立思考
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)