欢迎访问欧博亚洲(Allbet Game)!

首页科技正文

新余之窗网:手写一个浅易的多周期 MIPS CPU

admin2020-05-1642

一点前言

多周期 CPU 相比单周期 CPU 以及流水线的实现来说实在写起来要贫苦那么一些,然则相对于流水线以及单周期 CPU 而言,多周期 CPU 除了能提升主频之外似乎并没有什么卵用。不外我的课题是多周期 CPU 那么就最先吧。

多周期 CPU

差别于单周期 CPU,多周期 CPU 指的是将整个 CPU 的执行历程分成几个阶段,每个阶段用一个时钟去完 成,然后最先下一条指令的执行,而每种指令执行时所用的时钟数不尽相同,这就是所谓的多周期CPU。

CPU在处置指令时,一样平常需要经由以下几个阶段:

(1) 取指令(IF):凭据程序计数器 PC 中的指令地址,从存储器中取出一条指令,同时,PC 凭据指令字长度自动递增发生下一条指令所需要的指令地址,但遇到“地址转移”指令 时,则控制器把“转移地址”送入 PC,固然获得的“地址”需要做些变换才送入 PC。

(2) 指令译码(ID):对取指令操作中获得的指令举行剖析并译码,确定这条指令需要完成的操作,从而发生响应的操作控制信号,用于驱动执行状态中的种种操作。

(3) 指令执行(EXE):凭据指令译码获得的操作控制信号,详细地执行指令动作,然后转移到效果写回状态。

(4) 存储器接见(MEM):所有需要接见存储器的操作都将在这个步骤中执行,该步骤给出存储器的数据地址,把数据写入到存储器中数据地址所指定的存储单元或者从存储器中得 到数据地址单元中的数据。

(5) 效果写回(WB):指令执行的效果或者接见存储器中获得的数据写回响应的目的寄存器中。

这也就意味着一条 CPU 指令最长需要 5 个时钟周期才气执行完毕,至于详细需要若干周期则凭据指令的差别而差别。

MIPS 指令集的设计为定长简朴指令集,这为 CPU 的实现带来了极大的利便。

指令集

MIPS 指令分为三种:R、I 和 J,三种指令有差别的存储方式:

其中,

  • op:操作码;
  • rs:第1个源操作数寄存器,寄存器地址(编号)是00000~11111,00~1F;
  • rt:第2个源操作数寄存器,或目的操作数寄存器,寄存器地址(同上);
  • rd:目的操作数寄存器,寄存器地址(同上);
  • sa:位移量(shift amt),移位指令用于指定移若干位;
  • funct:功效码,在寄存器类型指令中(R类型)用来指定指令的功效;
  • immediate:16位立刻数,用作无符号的逻辑操作数、有符号的算术操作数、数据加载(Load)/数据保留(Store)指令的数据地址字节偏移量和分支指令中相对程序计数器(PC)的有符号偏移量;
  • address:地址。

在执行指令的历程中,需要在差别的时钟周期之间举行状态转移:

本浅易 CPU 临时只实现以下指令:

OpCode 指令 功效
000000 add rd, rs, rt 带符号加法运算
000001 sub rd, rs, rt 带符号减法运算
000010 addiu rt, rs, immediate 无符号加法运算
010000 and rd, rs, rt 与运算
010001 andi rt, rs, immediate 对立刻数做 0 扩展后举行与运算
010010 ori rt, rs, immediate 对立刻数做 0 扩展后做或运算
010011 xori rt, rs, immediate 对立刻数做 0 扩展后做异或运算
011000 sll rd, rt, sa 左移指令
100110 slti rt, rs, immediate 对照指令
100111 slt rd, rs, rt 对照指令
110000 sw rt, immediate(rs) 存数指令
110001 lw rt, immediate(rs) 读数指令
110100 beq rs, rt, immediate 分支指令,相等时跳转
110101 bne rs, rt, immediate 分支指令,不等时跳转
110110 bltz rs, immediate 分支指令,小于 0 时跳转
111000 j addr 跳转指令
111001 jr rs 跳转指令
111010 jal addr 挪用子程序指令
111111 halt 停机指令

控制单元

一个浅易的多周期 CPU 的数据通路图如下:

三个 D 触发器用于保留当前状态,是时序逻辑电路,RST用于初始化状态“000“,另外两个部门都是组合逻辑电路,一个用于发生 下一个阶段的状态,另一个用于发生每个阶段的控制信号。从图上可看出,下个状态取决于 指令操作码和当前状态;而每个阶段的控制信号取决于指令操作码、当前状态和反映运算效果的状态 zero 标志和符号 sign标志。

其中指令和数据各存储在差别存储器中,即有指令存储器和数据存储器。接见存储器时,先给出内存地址,然后由读或写信号控制操作。对于寄存器组, 给出寄存器地址(编号),读操作时不需要时钟信号,输出端就直接输出响应数据;而在写操作时,在 WE使能信号为 1时,在时钟边缘触发将数据写入寄存器。

IR 指令寄存器目的是使指令代码保持稳定,PC 写使能控制信号PCWre,是确保PC 适时修改,缘故原由都是和多周期事情的CPU有关。ADR、BDR、 ALUoutDR、DBDR四个寄存器不需要写使能信号,其作用是切分数据通路,将大组合逻辑切分为若干个小组合逻辑,大延迟变为多个分段小延迟。

各控制信号功效如下:

控制信号名 状态 0 状态 1
RST 对于PC,初始化PC为程序首地址 对于PC,PC吸收下一条指令地址
PCWre PC不更改,另 外,除‘000’状态之外,其余状态慎改PC的值。 PC更改,另外,在‘000’状态时,修改PC的值合适。
ALUSrcA 来自寄存器堆 data1 输出 来自移位数sa,同时,举行(zeroextend)sa,即 {{27{1'b0},sa}
ALUSrcB 来自寄存器堆 data2 输出 来自 sign或 zero 扩展的立刻数
DBDataSrc 来自ALU运算效果的输出 来自数据存储器(Data MEM)的输出
RegWre 无写寄存器组寄存器 寄存器组寄存器写使能
WrRegDSrc 写入寄存器组寄存器的数据来自 PC+4(PC4) 写入寄存器组寄存器的数据来自ALU 运算效果或存储器读出的数据
InsMemRW 写指令存储器 读指令存储器(Ins. Data)
mRD 存储器输出高阻态 读数据存储器
mWR 无操作 写数据存储器
IRWre IR(指令寄存器)不更改 IR 寄存器写使能。向指令存储器发出读指令代码后,这个信号也接着发出,在时钟上升沿,IR 吸收从指令存储器送来的指令代码。
ExtSel 零扩展 符号扩展
PCSrc[1..0] 00:PC<-PC+4
01:PC<-PC+4+((sign-extend)immediate<<2)
10:PC<-rs
11:PC<-{PC[31:28], addr[27:2],2'b00}
RegDst[1..0] 写寄存器组寄存器的地址,来自:
00:0x1F($31)
01:rt 字段
10:rd 字段
11:未用
ALUOp[2..0] ALU 8种运算功效选择(000-111)

相关部件及引脚说明

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,负数

ALU

ALU 为算术逻辑运算单元,功效如下:

ALUOp[2..0] 功效 功效
000 Y=A+B 加法运算
001 Y=A-B 减法运算
010 Y=B<<A 左移运算
011 Y=A∨B 或运算
100 Y=A∧B 与运算
101 Y=(A<B) ? 1 : 0 无符号对照
110 Y=(((A<B)&&(A[31] == B[31])) ||
((A[31]==1&& B[31] == 0))) ? 1 : 0
带符号对照
111 Y=A⊕B 异或

模块设计

符号界说

为了加倍明晰程序代码,并制止因二进制代码誊写错误导致的问题,对状态码、操 作码等做出如下界说:

`define ALU_OP_ADD 3'b000
`define ALU_OP_SUB 3'b001
`define ALU_OP_SLL 3'b010
`define ALU_OP_OR 3'b011
`define ALU_OP_AND 3'b100
`define ALU_OP_LT 3'b101
`define ALU_OP_SLT 3'b110
`define ALU_OP_XOR 3'b111

`define OP_ADD 6'b000000
`define OP_SUB 6'b000001
`define OP_ADDIU 6'b000010
`define OP_AND 6'b010000
`define OP_ANDI 6'b010001
`define OP_ORI 6'b010010
`define OP_XORI 6'b010011
`define OP_SLL 6'b011000
`define OP_SLTI 6'b100110
`define OP_SLT 6'b100111
`define OP_SW 6'b110000
`define OP_LW 6'b110001
`define OP_BEQ 6'b110100
`define OP_BNE 6'b110101
`define OP_BLTZ 6'b110110
`define OP_J 6'b111000
`define OP_JR 6'b111001
`define OP_JAL 6'b111010
`define OP_HALT 6'b111111

`define PC_NEXT 2'b00
`define PC_REL_JUMP 2'b01
`define PC_REG_JUMP 2'b10
`define PC_ABS_JUMP 2'b11

`define STATE_IF 3'b000
`define STATE_ID 3'b001
`define STATE_EXE_AL 3'b110
`define STATE_EXE_BR 3'b101
`define STATE_EXE_LS 3'b010
`define STATE_MEM 3'b011
`define STATE_WB_AL 3'b111
`define STATE_WB_LD 3'b100

控制单元

状态转移

always @(posedge CLK or negedge RST) begin
    if (!RST) State <= `STATE_IF;
    else begin
        case (State)
            `STATE_IF: State <= `STATE_ID;
            `STATE_ID: begin
                case (OpCode)
                    `OP_ADD, `OP_SUB, `OP_ADDIU, `OP_AND, `OP_ANDI, `OP_ORI, 
                    `OP_XORI, `OP_SLL, `OP_SLTI, `OP_SLT: State <= `STATE_EXE_AL;
                    `OP_BNE, `OP_BEQ, `OP_BLTZ: State <= `STATE_EXE_BR;
                    `OP_SW, `OP_LW: State <= `STATE_EXE_LS;
                    `OP_J, `OP_JAL, `OP_JR, `OP_HALT: State <= `STATE_IF;
                    default: State <= `STATE_EXE_AL;
                endcase
            end
            `STATE_EXE_AL: State <= `STATE_WB_AL;
            `STATE_EXE_BR: State <= `STATE_IF;
            `STATE_EXE_LS: State <= `STATE_MEM;
            `STATE_WB_AL: State <= `STATE_IF;
            `STATE_MEM: begin
                case (OpCode)
                    `OP_SW: State <= `STATE_IF;
                    `OP_LW: State <= `STATE_WB_LD;
                endcase
            end
            `STATE_WB_LD: State <= `STATE_IF;
            default: State <= `STATE_IF;
        endcase
    end
end

控制信号

差别控制信号凭据差别的操作码获得,因此可以列出对于差别操作码的各控制信号的真值表:

Op PCWre ALUSrcA ALUSrcB DBDataSrc RegWre WrRegDSrc InsMemRW mRD mWR IRWre ExtSel PCSrc RegDst ALUOp
add 0 0 0 0 1 1 1 X X 1 X 00 10 000
sub 0 0 0 0 1 1 1 X X 1 X 00 10 001
addiu 0 0 1 0 1 1 1 X X 1 1 00 01 000
and 0 0 0 0 1 1 1 X X 1 X 00 10 100
andi 0 0 1 0 1 1 1 X X 1 0 00 01 100
ori 0 0 1 0 1 1 1 X X 1 0 00 01 011
xori 0 0 1 0 1 1 1 X X 1 0 00 01 111
sll 0 1 0 0 1 1 1 X X 1 X 00 10 010
slti 0 0 1 0 1 1 1 X X 1 1 00 01 110
slt 0 0 0 0 1 1 1 X X 1 X 00 10 110
sw 0 0 1 X 0 X 1 X 1 1 1 00 XX 000
lw 0 0 1 1 1 1 1 1 X 1 1 00 01 000
beq 0 0 0 X 0 X 1 X X 1 1 00(Zero=0) 01(Zero=1) XX 001
bne 0 0 0 X 0 X 1 X X 1 1 00(Zero=1) 01(Zero=0) XX 001
bltz 0 0 0 X 0 X 1 X X 1 1 00(Sign=0) 01(Sign=1) XX 001
j 0 X X X 0 X 1 X X 1 X 11 XX XXX
jr 0 X X X 0 X 1 X X 1 X 10 XX XXX
jal 0 X X X 1 0 1 X X 1 X 11 00 XXX
halt 1 X X X 0 X 1 X X 1 X XX XX XXX

控制信号不仅仅取决于操作码,还取决于当前的状态。各控制信号实现如下:

ALUSrcA:EXE 阶段 LS、SLL

ALUSrcA = ((State == `STATE_EXE_AL || State == `STATE_EXE_BR || State == `STATE_EXE_LS) && OpCode == `OP_SLL) ? 1 : 0;

ALUSrcB:EXE 阶段 ADDIU、ANDI、ORI、XORI、SLTI、LW、SW

ALUSrcB = ((State == `STATE_EXE_AL || State == `STATE_EXE_BR || State == `STATE_EXE_LS) && (OpCode == `OP_ADDIU || OpCode == `OP_ANDI || OpCode == `OP_ORI || OpCode == `OP_XORI || OpCode == `OP_SLTI || OpCode == `OP_LW || OpCode == `OP_SW)) ? 1 : 0;

RegWre:ID 阶段 JAL,或 WB 阶段 LD

RegWre = ((State == `STATE_ID && OpCode == `OP_JAL) || (State == `STATE_WB_AL || State == `STATE_WB_LD)) ? 1 : 0;

WrRegDSrc:ID 阶段 JAL

WrRegDSrc = (State == `STATE_ID && OpCode == `OP_JAL) ? 0 : 1;

mRD:MEM 或 WB 阶段 LW

mRD = ((State == `STATE_MEM || State == `STATE_WB_LD) && OpCode == `OP_LW) ? 1 : 0;

mWR:MEM 阶段 SW

mWR = (State == `STATE_MEM && OpCode == `OP_SW) ? 1 : 0;

IRWre:IF 阶段

IRWre = (State == `STATE_IF) ? 1 : 0;

ExtSel:EXE 阶段 ANDI、ORI、XORI

ExtSel = ((State == `STATE_EXE_AL || State == `STATE_EXE_BR || State == `STATE_EXE_LS) && (OpCode == `OP_ANDI || OpCode == `OP_ORI || OpCode == `OP_XORI)) ? 0 : 1;

PCSrc:IF 或 ID 阶段 JR 为 PC_REG_JUMP,IF 或 ID 阶段 J、JAL 为 PC_ABS_JUMP,EXE 阶段 BEQ、BNE、BLTZ 为 PC_REL_JUMP,否则均为 PC_NEXT

if ((State == `STATE_IF || State == `STATE_ID) && OpCode == `OP_JR) PCSrc = `PC_REG_JUMP;
else if ((State == `STATE_IF || State == `STATE_ID) && (OpCode == `OP_J || OpCode == `OP_JAL)) PCSrc = `PC_ABS_JUMP;
else if ((State == `STATE_EXE_AL || State == `STATE_EXE_BR || State == `STATE_EXE_LS) && (OpCode == `OP_BEQ && Zero) || (OpCode == `OP_BNE && !Zero) || (OpCode == `OP_BLTZ && Sign)) PCSrc = `PC_REL_JUMP;
else PCSrc = `PC_NEXT;

RegDst:ID 阶段 JAL 为 b00,WB 阶段 ADDIU、ANDI、ORI、XORI、SLTI、LW 为 b01,否则均为 b10

if (State == `STATE_ID && OpCode == `OP_JAL) RegDst = 2'b00;
else if ((State == `STATE_WB_AL || State == `STATE_WB_LD) && (OpCode == `OP_ADDIU || OpCode == `OP_ANDI || OpCode == `OP_ORI || OpCode == `OP_XORI || OpCode == `OP_SLTI || OpCode == `OP_LW)) RegDst = 2'b01;
else RegDst = 2'b10;

ALUOp:凭据真值表即可得出

case (OpCode)
    `OP_ADD, `OP_ADDIU, `OP_SW, `OP_LW: ALUOp = `ALU_OP_ADD;
    `OP_SUB, `OP_BEQ, `OP_BNE, `OP_BLTZ: ALUOp = `ALU_OP_SUB;
    `OP_SLL: ALUOp = `ALU_OP_SLL;
    `OP_ORI: ALUOp = `ALU_OP_OR;
    `OP_AND, `OP_ANDI: ALUOp = `ALU_OP_AND;
    `OP_SLTI, `OP_SLT: ALUOp = `ALU_OP_SLT;
    `OP_XORI: ALUOp = `ALU_OP_XOR;
endcase

PCWre:ID 阶段 J、JAL、JR,或 EXE 阶段 BEQ、BNE、BLTZ,或 MEM 阶段 SW,或 WB 阶段。另外,为保证在每条指令最初阶段的时钟上升沿 PC 发生改变,需要在上一条指令的最后一个下降沿将 PCWre 设置为 1,这样才气保证 PC 在每条指令最最先的时钟上升沿改变。

always @(negedge CLK) begin
    case (State)
        `STATE_ID: begin
            if (OpCode == `OP_J || OpCode == `OP_JAL || OpCode == `OP_JR) PCWre <= 1;
        end
        `STATE_EXE_AL, `STATE_EXE_BR, `STATE_EXE_LS: begin
            if (OpCode == `OP_BEQ || OpCode == `OP_BNE || OpCode == `OP_BLTZ) PCWre <= 1;
        end
        `STATE_MEM: begin
            if (OpCode == `OP_SW) PCWre <= 1;
        end
        `STATE_WB_AL, `STATE_WB_LD: PCWre <= 1;
        default: PCWre <= 0;
    endcase
end

逻辑算术运算单元

该模块是一个32位的ALU单元,会凭据控制信号对输入的操作数举行差别的运算,例如加、减、与、或等。

module ALU(
    input [2:0] ALUOp,
    input [31:0] A,
    input [31:0] B,
    output Sign,
    output Zero,
    output reg [31:0] Result
    );

    always @(*) begin
        case (ALUOp)
            `ALU_OP_ADD: Result = (A + B);
            `ALU_OP_SUB: Result = (A - B);
            `ALU_OP_SLL: Result = (B << A);
            `ALU_OP_OR: Result = (A | B);
            `ALU_OP_AND: Result = (A & B);
            `ALU_OP_LT: Result = (A < B) ? 1 : 0;
            `ALU_OP_SLT: Result = (((A < B) && (A[31] == B[31])) || ((A[31] && !B[31]))) ? 1 : 0;
            `ALU_OP_XOR: Result = (A ^ B);
        endcase
        $display("[ALU] calculated result [%h] from a = [%h] aluOpCode = [%b] b = [%h]", Result, A, ALUOp, B);
    end
    
    assign Zero = (Result == 0) ? 1 : 0;
    assign Sign = Result[31];
    
endmodule

寄存器组

该模块为一个32位而拥有32个寄存的寄存器组。寄存器组接受 InstructionMemory 的输入,输出对应寄存器的数据,从而实现读取寄存器里的数据的功效。

module RegisterFile(
    input CLK,
    input RST,
    input WE,
    input [4:0] ReadReg1,
    input [4:0] ReadReg2,
    input [4:0] WriteReg,
    input [31:0] WriteData,
    output [31:0] ReadData1,
    output [31:0] ReadData2
    );
    
    reg [31:0] register[1:31];
    integer i;

    assign ReadData1 = ReadReg1 == 0 ? 0 : register[ReadReg1];
    assign ReadData2 = ReadReg2 == 0 ? 0 : register[ReadReg2];

    always @(negedge CLK or negedge RST) begin
        if (!RST) begin
            for (i = 1; i < 32; i = i + 1) begin
                register[i] = 0;
            end
        end
        else if (WE && WriteReg) begin
            register[WriteReg] <= WriteData;
            $display("[RegisterFile] wrote data [%h] into reg $[%d]", WriteData, WriteReg);
        end
    end
endmodule

符号扩展单元

该组件有两个功效:符号扩展和零扩展,输入的扩展方式和待扩展的数据,输出扩展后的数据。

module SignZeroExtend(
    input ExtSel, // 0 - 0 extend, 1 - sign extend
    input [15:0] Immediate,
    output [31:0] DataOut
    );
    
    assign DataOut[15:0] = Immediate[15:0];
    assign DataOut[31:16] = (ExtSel && Immediate[15]) ? 16'hFFFF : 16'h0000;
endmodule

指令存储器

把指令集以二进制的形式写成一个文件,然后在指令存储器中读进来,以读文件的方式把指令存储到内存中,实现指令的读取。

module InstructionMemory(
    input RW,
    input [31:0] IAddr,
    output reg [31:0] DataOut
    );
    
    reg [7:0] memory[0:95];
    
    initial begin
        $readmemb(`MEMORY_FILE_PATH, memory);
    end
    
    always @(IAddr or RW) begin
        if (RW) begin
            DataOut[31:24] = memory[IAddr];
            DataOut[23:16] = memory[IAddr + 1];
            DataOut[15:8] = memory[IAddr + 2];
            DataOut[7:0] = memory[IAddr + 3];
            $display("[InstructionMemory] Loaded instruction [%h] from address [%h]", DataOut, IAddr);
        end
    end
endmodule

数据存储单元

数据存储单元卖力存取数据,且由时钟下降沿出发写操作。实现为1字节8位的大端方式存储。

module DataMemory(
    input CLK,
    input mRD,
    input mWR,
    input [31:0] DAddr,
    input [31:0] DataIn,
    output [31:0] DataOut
    );

    reg [7:0] memory[0:127];
    
    assign DataOut[7:0] = mRD ? memory[DAddr + 3] : 8'bz; 
    assign DataOut[15:8] = mRD ? memory[DAddr + 2] : 8'bz;
    assign DataOut[23:16] = mRD ? memory[DAddr + 1] : 8'bz;
    assign DataOut[31:24] = mRD ? memory[DAddr] : 8'bz;
    
    always @(negedge CLK) begin
        if (mWR) begin
            memory[DAddr] <= DataIn[31:24];
            memory[DAddr + 1] <= DataIn[23:16];
            memory[DAddr + 2] <= DataIn[15:8];
            memory[DAddr + 3] <= DataIn[7:0];
            $display("[DataMemory] saved data [%h] into address [%h]", DataIn, DAddr);
        end
    end
endmodule

程序计数器

在时钟上升沿处给出下条指令的地址,或在重置信号下降沿处将PC归零。

PC的下一条指令可能是当前 PC+4,也可能是跳转指令地址,另有可能由于停机而稳定。 因此还需要设计一个选择器来选择下一条指令地址的盘算方式,为此创建了 JumpPCHelper用于盘算 j 指令的下一条 PC 地址,和 NextPCHelper 用于凭据指令选择差别的盘算方式。

module PC(
    input CLK,
    input RST,
    input PCWre,
    input [31:0] PCAddr,
    output reg [31:0] NextPCAddr
    );

    initial NextPCAddr = 0;

    always @(posedge CLK or negedge RST) begin
        if (!RST) NextPCAddr <= 0;
        else if (PCWre || !PCAddr) NextPCAddr <= PCAddr;
    end
endmodule

module JumpPCHelper(
    input [31:0] PC,
    input [25:0] NextPCAddr,
    output reg [31:0] JumpPC);

    wire [27:0] tmp;
    assign tmp = NextPCAddr << 2; // address * 4

    always @(*) begin
        JumpPC[31:28] = PC[31:28];
        JumpPC[27:2] = tmp[27:2];
        JumpPC[1:0] = 0;
    end
endmodule

module NextPCHelper(
    input RST,
    input [1:0] PCSrc,
    input [31:0] PC,
    input [31:0] Immediate,
    input [31:0] RegPC,
    input [31:0] JumpPC,
    output reg [31:0] NextPC);

    always @(RST or PCSrc or PC or Immediate or RegPC or JumpPC) begin
        if (!RST) NextPC = PC + 4;
        else begin
            case (PCSrc)
                `PC_NEXT: NextPC = PC + 4;
                `PC_REL_JUMP: NextPC = PC + 4 + (Immediate << 2);
                `PC_REG_JUMP: NextPC = RegPC;
                `PC_ABS_JUMP: NextPC = JumpPC;
                default: NextPC = PC + 4;
            endcase
        end
    end
endmodule

选择器

数据选择,用于数据存储单元之后的选择,这里需要二选一和三选一数据选择器。

module Selector1In2#(
    parameter WIDTH = 5
)(
    input Sel,
    input [WIDTH-1:0] A,
    input [WIDTH-1:0] B,
    output [WIDTH-1:0] Y);

    assign Y = Sel ? B : A;
endmodule

module Selector1In3#(
    parameter WIDTH = 5
)(
    input [1:0] Sel,
    input [WIDTH-1:0] A,
    input [WIDTH-1:0] B,
    input [WIDTH-1:0] C,
    output reg [WIDTH-1:0] Y);

    always @(Sel or A or B or C) begin
        case (Sel)
            2'b00: Y <= A;
            2'b01: Y <= B;
            2'b10: Y <= C;
            default: Y <= 0;
        endcase
    end
    
endmodule

指令寄存器

用时钟信号 CLK 驱动,接纳边缘触发写入指令二进制码。

module IR(
    input CLK,
    input IRWre,
    input [31:0] DataIn,
    output reg [31:0] DataOut
    );
    always @(posedge CLK) begin
        if (IRWre) begin
            DataOut <= DataIn;
        end
    end
endmodule

数据延迟处置

这部门模块用于切割数据通路。

module XDR(
    input CLK,
    input [31:0] DataIn,
    output reg [31:0] DataOut
    );
    always @(negedge CLK) DataOut <= DataIn;
endmodule

CPU

有了以上各个模块,一个简朴的 CPU 基本就完成了,最后再将他们串起来即可。

完结撒花。

,

皇冠会员APP

皇冠体育APP是一个开放皇冠代理APP下载、皇冠会员APP下载、皇冠线路APP下载、皇冠登录APP下载的平台,皇冠体育APP上最新登录线路、新2皇冠网址更新最快,皇冠体育APP开放皇冠会员注册、皇冠代理开户等业务。

转载声明:本站发布文章及版权归原作者所有,转载本站文章请注明文章来源:欧博亚洲(Allbet Game)!

本文链接:http://www.zbguandaobeng.com/post/1139.html

网友评论

最新评论

  • AllbetGmaing电脑版下载 09/26 说:

    欧博亚洲官方注册欢迎进入欧博亚洲官方注册(Allbet Game):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。生活又有希望啦

  • 欧博APP下载 09/26 说:

    allbet欧博真人客户端欢迎进入allbet欧博真人客户端(Allbet Game):v,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。拉你进夸夸群

  • UG环球客户端下载 09/25 说:

    Allbetwww.aLLbetgame.us欢迎进入Allbet平台(Allbet Gaming):www.aLLbetgame.us,欧博平台开放欧博(Allbet)开户、欧博(Allbet)代理开户、欧博(Allbet)电脑客户端、欧博(Allbet)APP下载等业务。这个不差的

  • AllbetGmaing代理 09/25 说:

    AllbetGmaing电脑版下载欢迎进入AllbetGmaing电脑版下载(www.aLLbetgame.us):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。看了就是一家人

  • UG环球官网 09/24 说:

    欧博亚洲官网开户网址欢迎进入欧博亚洲官网开户网址(Allbet Game):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。姐妹们快看神仙

  • UG环球官网 09/24 说:

    欧博亚洲官网开户网址欢迎进入欧博亚洲官网开户网址(Allbet Game):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。姐妹们快看神仙

  • 环球UG官方网 09/23 说:

    联博统计接口www.326681.com采用以太坊区块链高度哈希值作为统计数据,联博以太坊统计数据开源、公平、无任何作弊可能性。联博统计免费提供API接口,支持多语言接入。就是很好,谁损也没用

  • 环球UG充值 09/23 说:

    欧博app下载欢迎进入欧博app下载网站:www.aLLbetgame.us,欧博app下载网站是欧博官方网站。欧博app下载网站开放欧博注册、欧博代理、欧博电脑客户端、欧博app下载等业务。哈哈,我是死忠粉