无异常指令(共40条)
1.算术指令
- ADDIU
- ADDU
- SUBU
- MULU
- DIVU
- MUL
- DIV
2.逻辑指令
- AND
- ANDI
- NOR
- OR
- ORI
- XOR
- XORI
- LUI
3.移位指令
- SLLV
- SLL
- SRAV
- SRA
- SLT
- SLTI
- SLTIU
- SLTU
- SRL
- SRLV
4.分支跳转指令
- J
- JAL
- JR
- BEQ
- BNE
- BGEZ
- BGTZ
- BLEZ
- BLTZ
5.读写指令
- LW
- SW
6.数据移动
1.MFLO
2.MFHI
3.MTLO
4.MTHI
包括的模块
- mips模块是一个CPU,只含有复位信号rst和时钟信号clk,内部由PC、NPC、DM、IM、EXT、ALU、IR、Ctrl等模块以及一些多路选择器和缓冲器组成。
- PC(程序计数器):PC是指令计数器,主要功能是完成输出当前指令地址并保存下一条指令地址。复位后,PC指向0x0000_3000,此处为第一条指令的地址。
- NPC(NextPC计算单元):NPC是下条指令计数器,主要功能是计算下一条指令地址,NPCOp[1:0]决定如何计算NPC。
- Regfile(通用寄存器组,也称为寄存器文件、寄存器堆):RF主要功能是保存寄存器文件,并支持对通用寄存器的访问。
- ALU(算术逻辑单元):ALU主要功能是完成对输入数据的算数逻辑计算,包括加法、减法、按位或运算以及判断两个操作数是否相等。
- EXT(扩展单元):EXT主要功能是将16位的数据扩展为32位数据。
- IMEM(指令存储器):IM是指令存储器,主要功能是根据读控制信号DMWr,读写对应addr地址的32位数据。
- IR(指令寄存器):IR主要功能是完成对来自IM的指令的缓冲。
- DMEM(数据存储器):DM是数据存储器,主要功能是根据读写控制信号DMWr,读写对应addr地址的32位数据。
- MUX(数据选择器):主要功能是多路选择器。mux.v文件包含二选一、四选一、八选一、十六选一4中多路选择器。实例化多路选择器时,可使用#(XXX),实例化位宽为XXX的多路选择器。
- ICUT:主要功能是将32位指令分割为几个部分,传到不同的地方。
- MDU:进行乘除运算的单元
- define:对所有的名字进行宏定义。
模块
1.PC
端口说明
信号名 | 方向 | 描述 |
---|---|---|
Clk | I | 时钟信号 |
Rst | I | 复位信号 1:将PC置为初始值 0:无效 |
PCwr | I | PC读写使能端信号 1:可以写 0:不可写 |
PCin[31:0] | I | 下一条指令的地址 |
PCout[31:0] | O | 当前指令的地址(映射) |
功能定义
序号 | 功能 | 描述 |
---|---|---|
1 | 复位 | 将PC置为初始值 |
2 | 计数 | 当PCWR有效并且时钟上升沿,PC就更新为NPC的输出 |
2.IMEM
端口说明
信号名 | 方向 | 描述 |
---|---|---|
Addr | I | 当前指令的地址 |
Iout | O | 当前指令 |
功能定义
序号 | 功能 | 描述 |
---|---|---|
1 | 取指令 | 输出Addr地址所代表的当前指令 |
3.IR
端口说明
信号名 | 方向 | 描述 |
---|---|---|
clk | I | 时钟信号 |
IRin | I | 来自IMEM的指令 |
IRwr | I | 控制指令寄存器的读写 1:可以写 0:不可写 |
IRout | O | 当前指令 |
功能定义
序号 | 功能 | 描述 |
---|---|---|
1 | 缓冲 | 对来自IMEM的指令进行缓冲 |
4.Regfile
端口说明
信号名 | 方向 | 描述 |
---|---|---|
Clk | I | 时钟信号 |
rst | I | 重置信号 |
Ra[4:0] | I | 5位地址输入信号,将寄存器中的内容读出到Raout |
Rb[4:0] | I | 5位地址输入信号,将寄存器中的内容读出到Rbout |
Rw[4:0] | I | 5位地址输入信号,将寄存器作为目标寄存器 |
Wd[31:0] | I | 32位数据输入信号 |
IRwr | I | 控制IR读写 1:可写 0:不可写 |
Raout | O | 输出Raout所指定的寄存器中的32位数据 |
Rbout | O | 输出Rbout所指定的寄存器中的32位数据 |
功能定义
序号 | 功能 | 描述 |
---|---|---|
1 | 读数据 | 读出Ra,Rb地址所对应寄存器中1的数据到Raout,Rbout |
2 | 写数据 | 当RFwr有效且时钟上升沿来临,将Wd中的数据写入Rw所对应的寄存器中 |
5.ALU
端口说明
信号名 | 方向 | 描述 |
---|---|---|
A[31:0] | I | 操作数A |
B[31:0] | I | 操作数B |
ALUop[3:0] | I | 详见功能表 |
Out[31:0] | O | ALU输出结果为32位数据 |
功能定义
序号 | 功能 | 描述 |
---|---|---|
1 | 加运算 | 0000:Out = A + B |
2 | 减运算 | 0001:Out = A - B |
3 | 与运算 | 0010:Out = A & B |
4 | 或非运算 | 0011:Out = ~(A | B) |
5 | 异或运算 | 0100:Out = A ^ B |
6 | 或运算 | 0101:Out = A | B |
7 | 逻辑左移 | 0110:Out = B << A[10:6] |
8 | 逻辑右移 | 0111:Out = B >> A[10:6] |
9 | 算术右移 | 1000:Out = Signed(B) >>> A[10:6] |
10 | 小于置1(有符号) | 1001:Out = Signed(A) < Signed(B) ? 1 : 0 |
11 | 小于置1(无符号) | 1010:Out = A < B ? 1 : 0 |
12 | 将A操作数左移16位(LUI) | 1011:Out = A << 16 |
6.DMEM
端口说明
信号名 | 方向 | 描述 |
---|---|---|
DMwr | I | 数据存储器写使能信号 1:可写 0:无效 |
Addr[31:0] | I | 32位地址输入,指定读出或写入地址数据 |
Imm[31:0] | I | 经过拓展的32位立即数,用于计算地址 |
Din[31:0] | I | 32为数据输入 |
Dout[31:0] | O | 32为数据输出,由计算后的地址指定 |
功能定义
序号 | 功能 | 描述 |
---|---|---|
1 | 读数据 | 读出Addr所指定的数据到Dout |
2 | 计算地址 | 计算出由Addr和立即数相加的地址 |
3 | 写数据 | 当DMwr有效且时钟上升到来时,将输入的数据Din写到计算结果所指定的地址 |
7.EXT
端口说明
信号名 | 方向 | 描述 |
---|---|---|
EXTin | I | 16位输入数据 |
EXTop | I | 扩展方式选择信号 0:符号扩展 1:零扩展 |
EXTout | O | 扩展到32位后的输出数据 |
功能定义
序号 | 功能 | 描述 |
---|---|---|
1 | 符号扩展 | 将16位的输入数据进行符号扩展,输出32位数据 |
2 | 零扩展 | 将16位的输入数据进行零扩展,输出32位数据 |
8.NPC
端口说明
信号名 | 方向 | 描述 |
---|---|---|
Immj[25:0] | I | 跳转指令目的地址中间26位 |
ImmB[31:0] | I | 分支指令的偏移00量(分支选择时加上) |
PC[31:0] | I | 分支指令基地址 |
CmpA | I | 分支指令第一个比较数,指令为Jump时当做地址使用 |
CmpB | I | 分支指令第二个比较数 |
is_JR | I | 单独判断是不是JR指令 |
NPCop[2:0] | I | 详见功能表 |
JORB | I | 对Jump和Branch选择 0:Jump 1:Branch |
NPCout[31:0] | O | 从Jump和Branch里选出来的下一条指令地址 |
NextPC | O | 常规情况下PC + 4 |
功能定义
序号 | 功能 | 描述 |
---|---|---|
1 | 计算分支地址 | 先拓展立即数,根据比较结果来计算分支地址: 000:BEQ 001:BNE 010:BLEZ 011:BGTZ 100:BLTZ 101:BGEZ |
2 | 计算跳转地址 | 通过位拼接来计算得到跳转地址 |
9.MDU
端口说明
信号名 | 方向 | 描述 |
---|---|---|
clk | I | 时钟信号 |
rst | I | 重置信号 |
MDUressel | I | 读寄存器选择信号 0:读LO寄存器 1:读HI寄存器 |
A[31:0] | I | 参与计算的第一个值 |
B[31:0] | I | 参与计算的第二个值 |
MDUcoac | I | MDU使能端 |
MDUop[2:0] | I | MDU功能选择信号 000:{HI, LO} = $signed(A) * $signed(B) 001:{HI, LO} = A * B 010:LO = A / B, HI = A % B 011:LO = $signed(A) / $signed(B, HI = $signed(A) % $signed(B) 100:LO = A 101:HI = A |
MDUout[31:0] | O | 将计算结果输出 |
功能定义
序号 | 功能 | 描述 |
---|---|---|
1 | 无符号乘 | {HI, LO} = A * B |
2 | 有符号乘 | {HI, LO} = $signed(A) * $signed(B) |
3 | 无符号除 | LO = A / B, HI = A % B |
4 | 有符号除 | LO = $signed(A) / $signed(B, HI = $signed(A) % $signed(B) |
5 | 写LO寄存器 | LO = A |
6 | 读LO寄存器 | MDUout = LO |
7 | 写HI寄存器 | HI = A |
8 | 读HI寄存器 | MDUout = HI |
10.ICUT
端口说明
信号名 | 方向 | 描述 |
---|---|---|
Ins[31:0] | I | 传入的32位指令 |
op[5:0] | O | rs寄存器 |
rt[4:0] | O | rt寄存器 |
rd[4:0] | O | rd寄存器 |
rs[4:0] | O | 操作码 |
sa[4:0] | O | 位移量 |
Imm[15:0] | O | 立即数 |
Addr[25:0] | O | J指令地址片段 |
Insout[31:0] | O | 传给control的32位指令 |
功能定义
序号 | 功能 | 描述 |
---|---|---|
1 | 分割 | 将32位指令分割成片段,传到各个的端口中去 |
11.Control
端口说明
信号名 | 方向 | 描述 |
---|---|---|
Rst | I | 重置 |
Clk | I | 时钟信号 |
Ins | I | 32位指令,用来译码 |
PCwr | O | 控制PC是否可写 0:不可写 1:可写 |
IRwr | O | 控制IR是否可写 0:不可写 1:可写 |
Regin[1:0] | O | 选择写入Regfile的地址 00:写到rt寄存器 01:写到rd寄存器 10:写到1F寄存器 |
RFwr | O | 控制是否可以写入Regfile 0:不可写 1:可写 |
SEL_A | O | 选择A操作数 0:从Regfile中来 1:从EXT来 |
SEL_B | O | 选择B操作数 0:从Regfile中来 1:从EXT来 |
ALUop[3:0] | O | 控制ALU选择哪种运算,详见ALU功能描述 |
JORB | O | 控制NPCout选择Jump还是Branch 0:Jump 1:Branch |
NPCop[2:0] | O | 选择Branch的种类, 详见NPC功能描述 |
MDUressel | O | 读寄存器选择信号 0:读LO寄存器 1:读HI寄存器 |
MDUop[2:0] | O | 选择MDU的功能,详见功能描述 |
DMwr | O | 控制DM是否可写 0:不可写 1:可写 |
EXTop[1:0] | O | 控制扩展方式,详见功能表 |
WBsel[1:0] | O | 选择写回寄存器的数据从哪里来 |
NPCOsel | O | 选择正常执行下一条还是跳转分支 |
is_JR | O | 判断是不是将CMPA作为JR的地址使用 |
MDUcoac | O | MDU使能信号 1:可以进行计算 0:不可以进行计算 |
CPU数据数据通路图
状态对应信号
模块代码实现
1.ALU
module ALU(
input [31:0]A, // 操作数A
input [31:0]B, // 操作数B
input [3:0]ALUop, // 选择功能
output reg [31:0]Out // 输出结果
);
always @(*) begin
case(ALUop)
4'b0000: Out = A + B;
4'b0001: Out = A - B;
4'b0010: Out = A & B;
4'b0011: Out = A | B;
4'b0100: Out = A ^ B; // XOR
4'b0101: Out = ~(A | B); // NOR
4'b0110: Out = B << A[10:6]; // SLL
4'b0111: Out = B >> A[10:6]; // SRL
4'b1000: Out = $signed(B) >>> A[10:6]; // SRA
4'b1001: Out = ($signed(A) < $signed(B)) ? 1 : 0; // SLT和SLTI
4'b1010: Out = (A < B) ? 1 : 0; // SLTU和SLTIU
4'b1011: Out = A << 16; // LUI
endcase
end
endmodule
2.Control
`include "define.v"
module Control(
input clk, // 时钟信号
input rst, // 重置信号
input [31:0]Ins, // 传入的32位指令
output reg PCwr, // 控制PC是否能写入
output reg IRwr, // 控制IR是否能写入
output reg[1:0]Regin, // 进入Regfile的选择
output reg RFwr, // 控制Regfile是否能写入
output reg SEL_A, // 选入ALU的A操作数
output reg SEL_B, // 选入ALU的B操作数
output reg[3:0]ALUop, // ALU的操作
output reg JORB, // 判断是Jump还是Branch
output reg[2:0]NPCop, // 判断是哪种Branch
output reg MDUressel, // 选择是HI还是LO
output reg[2:0]MDUop, // MDU的操作
output reg DMwr, // DM使能信号
output reg[1:0]EXTop, // 是哪一种扩展
output reg[1:0]WBsel, // 写回的数据从哪里来
output reg NPCOsel, // 对NPC出来的结果进行选择(跳或者常态)
output reg is_JR, // 判断是不是JR, 需要将CmpA作为地址
output reg Dtype, // 判断DM是读还是写
output reg MDUcoac // MDU使能信号
);
parameter IF = 3'b000; // 取指
parameter ID = 3'b001; // 译码
parameter EXE = 3'b010; // 执行
parameter MEM = 3'b011; // 读取
parameter WB = 3'b100; // 写回
reg[2:0] CurrentState; // 当前状态
reg[2:0] NextState; // 下一状态
reg[5:0] Op;
/*时序逻辑*/
always @(posedge clk,posedge rst) begin
if(rst)
CurrentState <= IF;
else
CurrentState <= NextState;
end
always @(*) begin
case(CurrentState)
IF: begin
NextState = ID;
PCwr = 1'b0;
IRwr = 1'b1;
RFwr = 1'b0;
DMwr = 1'b0;
NPCOsel = 1'b0;
end
ID: begin
JORB = ~(Ins[`op] == `OP_J || Ins[`op] == `OP_JAL || (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_JR));
NPCOsel = (Ins[`op] == `OP_J || Ins[`op] == `OP_JAL || (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_JR));
//$display("NPCOsel = %8X", NPCOsel);
is_JR = (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_JR) ? 1'b1 : 1'b0;
case(Ins[`op])
`OP_J: begin
NextState = IF;
PCwr = 1'b1;
IRwr = 1'b0;
RFwr = 1'b0;
DMwr = 1'b0;
end
`OP_BEQ,`OP_BGEZ,`OP_BGTZ,
`OP_BLEZ,`OP_BLTZ,`OP_BNE: begin
NextState = EXE;
PCwr = 1'b0;
RFwr = 1'b0;
DMwr = 1'b0;
IRwr = 1'b0;
end
`OP_JAL: begin
NextState = IF;
PCwr = 1'b1;
IRwr = 1'b0;
RFwr = 1'b1;
DMwr = 1'b0;
Regin = 2'b10;
WBsel = 2'b11;
end
`OP_R:
case(Ins[`funct])
`FUNCT_JR: begin
NextState = IF;
PCwr = 1'b1;
IRwr = 1'b0;
RFwr = 1'b0;
DMwr = 1'b0;
end
default: begin
NextState = EXE;
PCwr = 1'b1; // 为了每次让PC + 4
RFwr = 1'b0;
DMwr = 1'b0;
IRwr = 1'b0;
MDUcoac = 1'b0;
end
endcase
default: begin
NextState = EXE;
PCwr = 1'b1;
RFwr = 1'b0;
DMwr = 1'b0;
IRwr = 1'b0;
end
endcase
end
EXE: begin
is_JR = 1'b0;
Regin =
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_DIV) ? 2'b00 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_DIVU) ? 2'b00 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_MULT) ? 2'b00 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_MULTU) ? 2'b00 :
2'b01;
SEL_A =
(Ins[`op] == `OP_LUI) ? 1'b1 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SLL) ? 1'b1 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SRL) ? 1'b1 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SRA) ? 1'b1 :
1'b0;
SEL_B =
(Ins[`op] == `OP_ADDIU || Ins[`op] == `OP_ANDI || Ins[`op] == `OP_ORI
|| Ins[`op] == `OP_XORI || Ins[`op] == `OP_SLTI || Ins[`op] == `OP_SLTIU);
ALUop =
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_ADDU) ? 4'b0000 :
(Ins[`op] == `OP_ADDIU) ? 4'b0000 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_AND) ? 4'b0010 :
(Ins[`op] == `OP_ANDI) ? 4'b0010 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_OR) ? 4'b0011 :
(Ins[`op] == `OP_ORI) ? 4'b0011 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_XOR) ? 4'b0100 :
(Ins[`op] == `OP_XORI) ? 4'b0100 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SLL) ? 4'b0110 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SLLV) ? 4'b0110 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SRA) ? 4'b1000 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SRAV) ? 4'b1000 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SLT) ? 4'b1001 :
(Ins[`op] == `OP_SLTI) ? 4'b1001 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SLTU) ? 4'b1010 :
(Ins[`op] == `OP_SLTIU) ? 4'b1010 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SRL) ? 4'b0111 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SRLV) ? 4'b0111 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SUBU) ? 4'b0001 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_NOR) ? 4'b0101 :
(Ins[`op] == `OP_LUI) ? 4'b1011 :
4'b1111;
JORB =
(Ins[`op] == `OP_BEQ) ? 1'b1 :
(Ins[`op] == `OP_BNE) ? 1'b1 :
(Ins[`op] == `OP_BLEZ && Ins[`rt] == `RT_BLEZ) ? 1'b1 :
(Ins[`op] == `OP_BGTZ && Ins[`rt] == `RT_BGTZ) ? 1'b1 :
(Ins[`op] == `OP_BLTZ && Ins[`rt] == `RT_BLTZ) ? 1'b1 :
(Ins[`op] == `OP_BGEZ && Ins[`rt] == `RT_BGEZ) ? 1'b1 :
1'b0;
NPCop =
(Ins[`op] == `OP_BEQ) ? 3'b000 :
(Ins[`op] == `OP_BNE) ? 3'b001 :
(Ins[`op] == `OP_BLEZ && Ins[`rt] == `RT_BLEZ) ? 3'b010 :
(Ins[`op] == `OP_BGTZ && Ins[`rt] == `RT_BGTZ) ? 3'b011 :
(Ins[`op] == `OP_BLTZ && Ins[`rt] == `RT_BLTZ) ? 3'b100 :
(Ins[`op] == `OP_BGEZ && Ins[`rt] == `RT_BGEZ) ? 3'b101 :
3'b111;
MDUop =
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_MULT) ? 3'b000 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_MULTU) ? 3'b001 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_DIV) ? 3'b011 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_DIVU) ? 3'b010 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_MTLO) ? 3'b100 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_MTHI) ? 3'b101 :
3'b111;
EXTop =
(Ins[`op] == `OP_ADDIU) ? 2'b00 :
(Ins[`op] == `OP_ANDI) ? 2'b01 :
(Ins[`op] == `OP_ORI) ? 2'b01 :
(Ins[`op] == `OP_XORI) ? 2'b01 :
(Ins[`op] == `OP_LUI) ? 2'b01 :
2'b00;
NPCOsel =
(Ins[`op] == `OP_BEQ) ? 1'b1 :
(Ins[`op] == `OP_BNE) ? 1'b1 :
(Ins[`op] == `OP_BLEZ && Ins[`rt] == `RT_BLEZ) ? 1'b1 :
(Ins[`op] == `OP_BGTZ && Ins[`rt] == `RT_BGTZ) ? 1'b1 :
(Ins[`op] == `OP_BLTZ && Ins[`rt] == `RT_BLTZ) ? 1'b1 :
(Ins[`op] == `OP_BGEZ && Ins[`rt] == `RT_BGEZ) ? 1'b1 :
1'b0;
MDUcoac =
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_DIV) ? 1'b1 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_DIVU) ? 1'b1 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_MULT) ? 1'b1 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_MULTU) ? 1'b1 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_MTLO) ? 1'b1 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_MTHI) ? 1'b1 :
1'b0;
case(Ins[`op])
`OP_R,`OP_ADDI,`OP_ADDIU,
`OP_ANDI,`OP_ORI,`OP_XORI,`OP_SLTI,`OP_SLTIU,`OP_LUI: begin
if (Ins[`funct] == `FUNCT_DIV || Ins[`funct] == `FUNCT_DIVU ||
Ins[`funct] == `FUNCT_MULT || Ins[`funct] == `FUNCT_MULTU ||
Ins[`funct] == `FUNCT_MTLO || Ins[`funct] == `FUNCT_MTHI) begin
NextState = IF;
PCwr = 1'b0;
RFwr = 1'b0;
DMwr = 1'b0;
IRwr = 1'b0;
end
else begin
NextState = WB;
PCwr = 1'b0;
RFwr = 1'b0;
DMwr = 1'b0;
IRwr = 1'b0;
end
end
`OP_BEQ,`OP_BGEZ,`OP_BGTZ,
`OP_BLEZ,`OP_BLTZ,`OP_BNE: begin
NextState = IF;
PCwr = 1'b1;
RFwr = 1'b0;
DMwr = 1'b0;
IRwr = 1'b0;
end
default: begin
NextState = MEM;
PCwr = 1'b0;
RFwr = 1'b0;
DMwr = 1'b0;
IRwr = 1'b0;
end
endcase
end
MEM: begin
case(Ins[`op])
`OP_LW: begin
NextState = WB;
PCwr = 1'b0;
RFwr = 1'b1;
DMwr = 1'b0;
IRwr = 1'b0;
//Dtype = 1'b0;
end
default: begin
NextState = IF;
PCwr = 1'b0;
RFwr = 1'b0;
DMwr = 1'b1;
IRwr = 1'b0;
//Dtype = 1'b1;
end
endcase
end
WB: begin
Regin =
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_ADDU) ? 2'b01 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SUBU) ? 2'b01 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_AND) ? 2'b01 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_OR) ? 2'b01 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_XOR) ? 2'b01 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_NOR) ? 2'b01 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SLL) ? 2'b01 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SLLV) ? 2'b01 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SRL) ? 2'b01 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SRLV) ? 2'b01 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SRA) ? 2'b01 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SRAV) ? 2'b01 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SLT) ? 2'b01 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_SLTU) ? 2'b01 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_MFLO) ? 2'b01 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_MFHI) ? 2'b01 :
(Ins[`op] == `OP_ADDIU) ? 2'b00 :
(Ins[`op] == `OP_ANDI) ? 2'b00 :
(Ins[`op] == `OP_ORI) ? 2'b00 :
(Ins[`op] == `OP_XORI) ? 2'b00 :
(Ins[`op] == `OP_LUI) ? 2'b00 :
(Ins[`op] == `OP_SLTI) ? 2'b00 :
(Ins[`op] == `OP_SLTIU) ? 2'b00 :
(Ins[`op] == `OP_LW) ? 2'b00 :
0;
MDUressel = (Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_MFHI) ? 1'b1 : 1'b0;
WBsel =
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_MFLO) ? 2'b01 :
(Ins[`op] == `OP_R && Ins[`funct] == `FUNCT_MFHI) ? 2'b01 :
(Ins[`op] == `OP_LW) ? 2'b10 :
2'b00;
NextState = IF;
PCwr = 1'b0;
RFwr = 1'b1;
DMwr = 1'b0;
IRwr = 1'b0;
end
endcase
end
endmodule
3.define
/*指令分段*/
`define op 31:26
`define funct 5:0
`define imm26 25:0
`define imm16 15:0
`define rs 25:21
`define rt 20:16
`define rd 15:11
`define s 10:6
/*ALU操作*/
`define ALUop_ADD 4'b0000
`define ALUop_SUB 4'b0001
`define ALUop_AND 4'b0010
`define ALUop_OR 4'b0011
`define ALUop_XOR 4'b0100
`define ALUop_NOR 4'b0101
`define ALUop_SLL 4'b0110
`define ALUop_SRL 4'b0111
`define ALUop_SRA 4'b1000
`define ALUop_SLT 4'b1001
`define ALUop_SLTU 4'b1010
`define ALUop_LUI 4'b1011
/*EXTop*/
`define EXT_SIGN 2'b00
`define EXT_ZERO 2'b01
/******* OP 操作码 *******/
`define OP_R 6'b000000
/******* 存储读取指令 *******/
`define OP_LW 6'b100011
`define OP_LUI 6'b001111
`define OP_SW 6'b101011
/******* I TYPE *******/
`define OP_ADDI 6'b001000
`define OP_ADDIU 6'b001001
`define OP_ANDI 6'b001100
`define OP_ORI 6'b001101
`define OP_SLTI 6'b001010
`define OP_SLTIU 6'b001011
`define OP_XORI 6'b001110
/******* BRANCH TYPE *******/
`define OP_BEQ 6'b000100
`define OP_BGEZ 6'b000001
`define OP_BGTZ 6'b000111
`define OP_BLEZ 6'b000110
`define OP_BLTZ 6'b000001
`define OP_BNE 6'b000101
/******* J TYPE *******/
`define OP_J 6'b000010
`define OP_JAL 6'b000011
//功能码
`define FUNCT_ADD 6'b100000
`define FUNCT_SUB 6'b100010
`define FUNCT_ADDU 6'b100001
`define FUNCT_SUBU 6'b100011
`define FUNCT_AND 6'b100100
`define FUNCT_OR 6'b100101
`define FUNCT_NOR 6'b100111
`define FUNCT_XOR 6'b100110
`define FUNCT_SLL 6'b000000
`define FUNCT_SLLV 6'b000100
`define FUNCT_SRL 6'b000010
`define FUNCT_SRLV 6'b000110
`define FUNCT_SRA 6'b000011
`define FUNCT_SRAV 6'b000111
`define FUNCT_SLT 6'b101010
`define FUNCT_SLTU 6'b101011
`define FUNCT_JALR 6'b001001
`define FUNCT_JR 6'b001000
`define FUNCT_MULT 6'b011000
`define FUNCT_MULTU 6'b011001
`define FUNCT_DIV 6'b011010
`define FUNCT_DIVU 6'b011011
`define FUNCT_MFHI 6'b010000
`define FUNCT_MFLO 6'b010010
`define FUNCT_MTHI 6'b010001
`define FUNCT_MTLO 6'b010011
//B_type_opcode
`define RT_BGEZ 5'b00001
`define RT_BGTZ 5'b00000
`define RT_BLEZ 5'b00000
`define RT_BLTZ 5'b00000
4.DMEM
module DMEM(
input clk, // 时钟信号
input DMwr, // DM写使能信号
input [31:0]Din, // 要写入DM的数据
input [31:0]Imm, // 用来计算地址的,扩展过的立即数
input [31:0]Addr, // 用来计算地址的rs中的内容
output reg[31:0]Dout // 从DM中输出的数据
);
reg [31:0] RAM[1023:0];
integer i;
initial begin // 初始时将所有内存单元初始化
for (i = 0; i < 1023; i = i + 1) RAM[i] = 32'b0;
end
always @(posedge clk) begin
if (DMwr) begin
RAM[Imm + Addr[11:2]] = Din; // 利用映射地址写入
//$display("%H",RAM[Addr[11:2]]);
end
else begin
Dout = RAM[Imm + Addr[11:2]]; // 利用映射地址读出
//$display("%H",RAM[Addr[11:2]]);
end
end
endmodule
5.EXT
module EXT(
input [15:0] EXTin, // 需要扩展的16位立即数
input EXTop, // 操作
output reg[31:0]EXTout // 扩展后的32位输出
);
always @(*) begin
if (EXTop) begin // 零扩展
EXTout = EXTin;
end
else EXTout = $signed(EXTin); // 符号扩展
end
endmodule
6.ICUT
module ICUT(
input [31:0]Ins,
output reg[4:0]rs, // 传入rs端口
output reg[4:0]rt, // 传入rt端口
output reg[4:0]rd, // 传入rd端口
output reg[15:0]Imm, // Imm传入EXT中拓展
output reg[25:0]Addr, // 地址片段传入NPC中
output reg[31:0]Insout // 不分割,直接送入Control进行译码
);
initial begin
rs = 5'b00000;
rt = 5'b00000;
rd = 5'b00000;
end
always @(Ins) begin
rs = Ins[25:21];
rt = Ins[20:16];
rd = Ins[15:11];
Imm = Ins[15:0];
Addr = Ins[25:0];
Insout = Ins;
end
endmodule
7.IMEM
module IMEM(
input [31:0]Addr,
output reg [31:0]Iout
);
reg [31:0] IM [1023:0];
initial
$readmemh("F:/MIPS_MULTI_CYCLE_CPU/test_app/test_12.txt", IM);
always@(*) begin
Iout <= IM[Addr[11:2]];
end
endmodule
8.IR
module IR(
input clk,
input IRwr,
input [31:0]IRin,
output reg [31:0]IRout
);
initial
IRout = 0;
always @(posedge clk) begin
if (IRwr) begin
IRout <= IRin;
end
end
endmodule
9.MDU
module MDU(
input clk, // 时钟信号
input rst, // 重置信号
input [31:0]A, // 操作数A
input [31:0]B, // 操作数B
input MDUressel, // 结果选择(HI/LO)
input MDUcoac, // MUD使能端
input [2:0]MDUop, // 操作选择
output [31:0]MDUout // 输出结果
);
reg [31:0]HI;
reg [31:0]LO;
assign MDUout = (MDUressel == 0) ? LO : HI;
always @(posedge clk) begin
if (rst) begin
HI = 0;
LO = 0;
end
else begin
if (MDUcoac) begin
case(MDUop)
3'b000: {HI,LO} = $signed(A) * $signed(B);
3'b001: {HI,LO} = A * B;
3'b010: if(B != 0) begin
LO = $signed(A) / $signed(B);
HI = $signed(A) % $signed(B);
end
3'b011: if(B != 0) begin
LO = A / B;
HI = A % B;
end
3'b100: begin
LO = A;
end
3'b101: begin
HI = A;
end
endcase
end
end
end
endmodule
10.mips
`timescale 1ns / 1ps
`include "define.v"
//
// Company:
// Engineer:
//
// Create Date: 2021/07/02 14:26:18
// Design Name:
// Module Name: mips
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module mips(
input clk,
input rst
);
//线网部分
// PC模块
wire PCwr;
wire [31:0]PCin;
wire [31:0]PCout;
// IMEM模块
wire [31:0]Iout;
// 拓展器模块
wire EXTop;
// IR模块
wire [31:0]IRout;
wire IRwr;
// ICUT模块
wire [4:0]rs;
wire [4:0]rt;
wire [4:0]rd;
wire [15:0]Imm;
wire [25:0]OutAddr;
wire [31:0]Insout;
// ICUT和RF之间的数据选择器
wire [1:0]Regin;
wire [4:0]CUT_MUX_RF_out;
// Regfile模块
wire [31:0]Wd;
wire RFwr;
wire [31:0]Raout;
wire [31:0]Rbout;
// NPC模块
wire JORB;
wire is_JR;
wire [2:0]NPCop;
wire [31:0]NextPC;
wire [31:0]NPCout;
// NPC和PC之间的数据选择器
wire NPCOsel;
// 操作数A选择器
wire [31:0]SEL_A_out;
wire [31:0]EXTout;
wire Sel_A;
// 操作数B选择器
wire [31:0]SEL_B_out;
wire Sel_B;
// ALU模块
wire [3:0]ALUop;
wire [31:0]ALUout;
// 数据存储器模块
wire DMwr;
wire Dtype;
wire [31:0]Dout;
// 乘除器单元
wire MDUressel;
wire MDUcoac;
wire [2:0]MDUop;
wire [31:0]MDUout;
// 写回寄存器的选择器
wire [1:0]WBsel;
// 模块实例化
PC U_PC(.clk(clk), .rst(rst), .PCwr(PCwr), .PCin(PCin), .PCout(PCout));
IMEM U_IMEM(.Addr(PCout), .Iout(Iout));
EXT U_EXT(.EXTin(Imm), .EXTop(EXTop), .EXTout(EXTout));
IR U_IR(.clk(clk), .IRwr(IRwr), .IRin(Iout), .IRout(IRout));
ICUT U_ICUT(.Ins(IRout), .rs(rs), .rt(rt), .rd(rd), .Imm(Imm), .Addr(OutAddr), .Insout(Insout));
MUX4#(5) CUT_MUX_RF(.In0(rt), .In1(rd), .In2(31), .Op(Regin), .Out(CUT_MUX_RF_out));
Regfile U_Regfile(.clk(clk), .rst(rst), .Ra(rs), .Rb(rt), .Rw(CUT_MUX_RF_out), .Wd(Wd), .RFwr(RFwr), .Raout(Raout), .Rbout(Rbout));
NPC U_NPC(.Immj(OutAddr), .ImmB(EXTout), .PC(PCout), .CmpA(Raout), .CmpB(Rbout), .is_JR(is_JR), .NPCop(NPCop), .JORB(JORB), .NPCout(NPCout), .NextPC(NextPC));
MUX2 NPC_TO_PC(.In0(NextPC), .In1(NPCout), .Op(NPCOsel), .Out(PCin));
MUX2 SEL_A(.In0(Raout), .In1(EXTout), .Op(Sel_A), .Out(SEL_A_out));
MUX2 SEL_B(.In0(Rbout), .In1(EXTout), .Op(Sel_B), .Out(SEL_B_out));
ALU U_ALU(.A(SEL_A_out), .B(SEL_B_out), .ALUop(ALUop), .Out(ALUout));
DMEM U_DMEM(.clk(clk), .DMwr(DMwr), .Din(Rbout), .Imm(EXTout), .Addr(Raout), .Dout(Dout));
MDU U_MDU(.clk(clk), .rst(rst), .A(Raout), .B(Rbout), .MDUressel(MDUressel), .MDUcoac(MDUcoac), .MDUop(MDUop), .MDUout(MDUout));
MUX4 WB_MUX(.In0(ALUout), .In1(MDUout), .In2(Dout), .In3(NextPC), .Op(WBsel), .Out(Wd));
Control U_Control(.clk(clk), .rst(rst), .Ins(Insout), .PCwr(PCwr), .IRwr(IRwr), .Regin(Regin), .RFwr(RFwr),
.SEL_A(Sel_A), .SEL_B(Sel_B), .ALUop(ALUop), .JORB(JORB), .NPCop(NPCop), .MDUressel(MDUressel),
.MDUop(MDUop), .DMwr(DMwr), .EXTop(EXTop), .WBsel(WBsel), .NPCOsel(NPCOsel), .is_JR(is_JR),
.Dtype(Dtype), .MDUcoac(MDUcoac));
endmodule
11.MUX
module MUX2
#(parameter width = 32)(
input [width-1:0] In0,
input [width-1:0] In1,
input Op,
output reg [width-1:0] Out
);
always @(*) begin
case (Op)
1'b0: Out = In0;
1'b1: Out = In1;
endcase
end
endmodule
module MUX4
#(parameter width = 32)(
input [width-1:0] In0,
input [width-1:0] In1,
input [width-1:0] In2,
input [width-1:0] In3,
input [1:0] Op,
output reg [width-1:0] Out
);
always @(*) begin
case (Op)
2'b00: Out = In0;
2'b01: Out = In1;
2'b10: Out = In2;
2'b11: Out = In3;
endcase
end
endmodule
module MUX8
#(parameter width = 32)(
input [width-1:0] In0,
input [width-1:0] In1,
input [width-1:0] In2,
input [width-1:0] In3,
input [width-1:0] In4,
input [width-1:0] In5,
input [width-1:0] In6,
input [width-1:0] In7,
input [2:0] Op,
output reg [width-1:0] Out
);
always @(*) begin
case (Op)
3'b000: Out = In0;
3'b001: Out = In1;
3'b010: Out = In2;
3'b011: Out = In3;
3'b100: Out = In4;
3'b101: Out = In5;
3'b110: Out = In6;
3'b111: Out = In7;
endcase
end
endmodule
12.NPC
module NPC(
input [25:0]Immj, // 分支指令立即数
input [31:0]ImmB, // 跳转指令立即数(偏移量)
input [31:0]PC, // 基地址
input [31:0]CmpA, // 分支比较数A
input [31:0]CmpB, // 分支比较数B
input [2:0]NPCop, // 选择分支
input is_JR, // 单独判断是不是JR
input JORB, // 选择输出是Jump还是Branch
output reg [31:0]NPCout, // Jump和Branch选出的下一条指令地址
output [31:0]NextPC // 常态下PC + 4
);
assign NextPC = PC + 4;
always @(*) begin
if (JORB) begin // JORB是1执行Branch
case(NPCop)
3'b000: NPCout = ($signed(CmpA) == $signed(CmpB)) ? (PC + (ImmB << 2) + 4) : (PC + 4); // BEQ
3'b001: NPCout = ($signed(CmpA) != $signed(CmpB)) ? (PC + (ImmB << 2) + 4) : (PC + 4); // BNE
3'b010: NPCout = ($signed(CmpA) <= 0) ? (PC + (ImmB << 2) + 4) : (PC + 4); // BLEZ
3'b011: NPCout = ($signed(CmpA) > 0) ? (PC + (ImmB << 2) + 4) : (PC + 4); // BGTZ
3'b100: NPCout = ($signed(CmpA) < 0) ? (PC + (ImmB << 2) + 4) : (PC + 4); // BLTZ
3'b101: NPCout = ($signed(CmpA) >= 0) ? (PC + (ImmB << 2) + 4) : (PC + 4); // BGEZ
endcase
end
else begin // JORB是0执行Jump
if (is_JR) begin
NPCout = CmpA;
end
else NPCout = {PC[31:28], Immj, 2'b00};
end
end
endmodule
13.PC
module PC(
input clk, // 时钟信号
input rst, // 重置信号
input PCwr, // PC写使能信号
input [31:0]PCin, // PC输入端口
output reg [31:0]PCout // PC 输出端口
);
always @(posedge clk or rst) begin
if (rst) begin
PCout <= 32'h0000_0000;
end
else if (PCwr) begin
PCout <= PCin;
end
end
endmodule
14.Regfile
module Regfile(
input clk, // 时钟信号
input rst, // 重置信号
input [4:0]Ra, // rs寄存器读入
input [4:0]Rb, // rt寄存器读入
input [4:0]Rw, // rd/rt寄存器读入
input [31:0]Wd, // 写入寄存器的数据
input RFwr, // 写寄存器使能信号
output reg [31:0]Raout, // 从rs中读出来的内容
output reg [31:0]Rbout // 从rt中读出来的内容
);
initial begin
Raout = 0;
Rbout = 0;
end
// 寄存器堆
reg [31:0] RF[31:0];
integer i;
initial begin
for (i = 0; i < 32; i = i + 1) RF[i] = 32'b0;
end
always@(Ra or Rb) begin
Raout <= RF[Ra];
Rbout <= RF[Rb];
end
always @(posedge clk) begin
if (rst) begin
for (i = 0; i < 32; i = i + 1) RF[i] = 32'b0;
end
else if (RFwr && Rw != 0) begin
RF[Rw] <= Wd;
//$display("Wd = %8X", Wd);
//$display("R[00-07]= %8X, %8X, %8X, %8X, %8X, %8X, %8X, %8X", 0, RF[1], RF[2], RF[3], RF[4], RF[5], RF[6], RF[7]);
//$display("R[08-15]= %8X, %8X, %8X, %8X, %8X, %8X, %8X, %8X", RF[8], RF[9], RF[10], RF[11], RF[12], RF[13], RF[14], RF[15]);
//$display("R[16-23]= %8X, %8X, %8X, %8X, %8X, %8X, %8X, %8X", RF[16], RF[17], RF[18], RF[19], RF[20], RF[21], RF[22], RF[23]);
//$display("R[24-31]= %8X, %8X, %8X, %8X, %8X, %8X, %8X, %8X", RF[24], RF[25], RF[26], RF[27], RF[28], RF[29], RF[30], RF[31]);
end
end
endmodule