赞
踩
1.MFLO
2.MFHI
3.MTLO
4.MTHI
信号名 | 方向 | 描述 |
---|---|---|
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的输出 |
信号名 | 方向 | 描述 |
---|---|---|
Addr | I | 当前指令的地址 |
Iout | O | 当前指令 |
序号 | 功能 | 描述 |
---|---|---|
1 | 取指令 | 输出Addr地址所代表的当前指令 |
信号名 | 方向 | 描述 |
---|---|---|
clk | I | 时钟信号 |
IRin | I | 来自IMEM的指令 |
IRwr | I | 控制指令寄存器的读写 1:可以写 0:不可写 |
IRout | O | 当前指令 |
序号 | 功能 | 描述 |
---|---|---|
1 | 缓冲 | 对来自IMEM的指令进行缓冲 |
信号名 | 方向 | 描述 |
---|---|---|
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所对应的寄存器中 |
信号名 | 方向 | 描述 |
---|---|---|
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 |
信号名 | 方向 | 描述 |
---|---|---|
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写到计算结果所指定的地址 |
信号名 | 方向 | 描述 |
---|---|---|
EXTin | I | 16位输入数据 |
EXTop | I | 扩展方式选择信号 0:符号扩展 1:零扩展 |
EXTout | O | 扩展到32位后的输出数据 |
序号 | 功能 | 描述 |
---|---|---|
1 | 符号扩展 | 将16位的输入数据进行符号扩展,输出32位数据 |
2 | 零扩展 | 将16位的输入数据进行零扩展,输出32位数据 |
信号名 | 方向 | 描述 |
---|---|---|
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 | 计算跳转地址 | 通过位拼接来计算得到跳转地址 |
信号名 | 方向 | 描述 |
---|---|---|
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 |
信号名 | 方向 | 描述 |
---|---|---|
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位指令分割成片段,传到各个的端口中去 |
信号名 | 方向 | 描述 |
---|---|---|
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:不可以进行计算 |
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
`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
/*指令分段*/ `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
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
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
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
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
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
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
`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
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
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
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
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
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。