【计算机组成原理】多周期 CPU 设计与实现

多周期CPU设计(Verilog)

多周期CPU设计与实现
有一个问题就是我只能做到在译码的上升沿获取指令的操作码,但是取数、存数指令,老师给的图要求取指阶段下一个是执行阶段。但就很矛盾,我在取指阶段根本无法获取指令操作码,所以不能根据指令操作码进行状态转移。
所以我的取数、存数就要加上译码阶段、什么也不干,当然,有获取指令操作码的作用。

关于vivado不显示寄存器和存储器的波形图
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

PC模块

module PC(
        input clk,
        input rst,
        input PCWre,//当为1时,pc等于新地址,否则不变
        input[15:0] newAddress,//新地址
        output reg[15:0] currentAddress//输出地址
        );
        initial begin
            currentAddress = 0;
        end
        always@(posedge clk or negedge rst)begin
            if(!rst)
                currentAddress = 0;
            else if(PCWre)
                currentAddress = newAddress;
            else
                currentAddress = currentAddress;
        end
endmodule

InsMemory模块

module InsMemory(
    input[15:0] addr,
    output reg[15:0] Ins
    );
    
    reg[15:0] unit[31:0];//32个16位存储单元
    initial begin
        unit[0] = 16'b0000_000_000000001;//取数,将数据存储器地址为1的数据送入寄存器堆地址为1的地方
        unit[1] = 16'b0001_000_001_000000;//加法,R[0] + R[1] -> R[0]
        unit[2] = 16'b0001_000_010_000000;//加法,R[0] + R[2] -> R[0]
        unit[3] = 16'b0001_000_011_000000;//加法,R[0] + R[3] -> R[0]
        
        unit[4] = 16'b0010_000000000111;//跳转,跳到第七条指令
        unit[5] = 16'b0001_000_100_000000;//加法,R[0] + R[4] -> R[0]
        unit[6] = 16'b0001_000_101_000000;//加法,R[0] + R[5] -> R[0]
        unit[7] = 16'b0001_000_110_000000;//加法,R[0] + R[6] -> R[0]
        
        unit[8] = 16'b0011_000_000000000;//存数,R[0]->Mem[0]
    end
    always@(*)begin
        Ins = unit[addr];
    end
    
endmodule

IR模块

//为了使指令代码保持稳定,并且有指令分割功能
module IR(
    input clk,
    input IRWre,
    input[15:0] Ins,
    output reg[3:0]op,
    output reg[2:0]r1,
    output reg[2:0]r2,
    output reg[8:0]addr,
    output reg[11:0]imm 
    );
    initial begin
        op = 0;
        r1 = 0;
        r2 = 0;
        addr = 0;
        imm = 0;
    end
    always@(posedge clk)begin
        if(IRWre)begin
            op = Ins[15:12];
            r1 = Ins[11:9];
            r2 = Ins[8:6];
            addr = Ins[8:0];
            imm = Ins[11:0];
        end
    end
endmodule

RegFile模块

module RegFile(
    input clk,
    input RegRW,
    input[2:0] read_reg1,
    input[2:0] read_reg2,
    input[15:0] write_data,//要写入的地址为read_reg1
    output[15:0] reg1,
    output[15:0] reg2 
    );
    integer i;
    reg[15:0] regfile[7:0];//有8个16位的寄存器
    initial begin
        for(i=0;i<8;i=i+1)
            regfile[i] = i;
    end
    always@(posedge clk)begin
        if(RegRW == 1)
            regfile[read_reg1] = write_data;
    end
    assign reg1 = regfile[read_reg1];
    assign reg2 = regfile[read_reg2];
endmodule

ALU模块

module ALU(
    alu_op, //ALU操作控制
    A,      //操作数A
    B,      //操作数B
    result  //运算结果
    );
    input[2:0] alu_op;
    input[15:0] A,B;
    output reg[15:0]result;
    
    always@(*)begin
        case(alu_op)
            3'b000 : result = A+B;
            3'b001 : result = A-B;
            3'b010 : result = A * B;
            3'b011 : result = A / B;
            3'b100 : result = A & B;
            3'b101 : result = A | B;
            3'b110 : result = A ^ B;
            3'b111 : result = A << B;
            default:result = 0;
        endcase
    end
endmodule

DataMemory模块

module DataMemory(
    input DataMemRW,
    input[8:0]DAddr,
    input[15:0]DataIn,
    output reg[15:0]DataOut
    );
    reg [15:0] memory[6'd63:0];//64个16位存储单元
    integer i;
    initial begin
        for(i=0;i<64;i=i+1)
            memory[i] = i*i;
        memory[1] = 16'd100;
    end
    
    always@(*)begin
        if(DataMemRW)
            memory[DAddr] = DataIn;
        else
            DataOut = memory[DAddr];
    end
    
endmodule

符号扩展模块

module SignZeroExtend(
    input[11:0]imm,
    output[15:0]extendImm
    );
    assign extendImm[11:0] = imm;
    assign extendImm[15:12] = imm[11] ?4'hf :4'h0;
endmodule

TempReg模块

//主要用于从RegFile读出的数据等过一个周期再送入ALU
module TempReg(
    input clk,
    input ALUSrc,
    input[15:0]inData,
    output reg[15:0]outData
    );
    initial begin
        outData = 0;
    end
    always@(posedge clk)begin
        if(ALUSrc)
            outData = inData;
    end
    
endmodule

Multiplexer16模块

module Multiplexer16(
    control, //选择信号,当为1时,输出in1,当为0时,输出in0
    in1,
    in0,
    out
    );
    input control;
    input[15:0] in1,in0;
    output[15:0] out;
    
    assign out = control ? in1:in0;
endmodule

ControlUnit模块

module ControlUnit(
    input clk,
    input rst,
    input[3:0] op,//指令操作码
    output reg PCWre,//为0时,pc值不变,否则为新地址
    output reg PCSrc,//为1时,新地址为跳转地址,为0时,新地址为pc+1
    output reg IRWre,
    output reg ALUSrcA,
    output reg ALUSrcB,
    output reg Mem_Alu,//当为1时,选择输出mem_out,否则输出alu_result
    output reg RegRW,
    output reg DataMemRW,
    output reg[2:0] alu_op
    );
    
    parameter[1:0]initState = 2'b11,
                    sIF = 2'b00,
                    sID = 2'b01,
                    sEXE = 2'b10;
                    
    reg[1:0] state,nextState;
    initial begin
        state = initState;
        PCWre = 0;
        PCSrc = 0;
        IRWre = 0;
        Mem_Alu = 0;
        ALUSrcA = 0;
        ALUSrcB = 0;
        RegRW = 0;
        DataMemRW = 0;
        alu_op = 0;     
    end
    
    always@(posedge clk)begin
        if(!rst)
            state = sIF;
        else begin
            state = nextState;
        end
    end
    always@(state or op)begin
        case(state)
            initState:nextState = sIF;
            sIF:nextState = sID;  
            sID:begin
                if(op == 4'b0010)//当为跳转指令,下一阶段是取指
                    nextState = sIF;
                else
                    nextState = sEXE;
            end
            sEXE:nextState = sIF;
            
        endcase
        
        if(nextState == sIF && state != initState)begin
            PCWre = 1;//PC更换为下一条指令地址
        end else
            PCWre = 0;

            
        if(state == sIF || nextState == sID)
            IRWre = 1;
        else
            IRWre = 0;
        
        
        
        if(op == 4'b0001)begin//加法指令
            ALUSrcA = 1;
            ALUSrcB = 1;
            alu_op = 0;
        end
        else begin
            ALUSrcA = 0;
            ALUSrcB = 0;
            alu_op = 0;
        end
        
        if(op == 4'b0010)begin
            PCSrc = 1;
        end
        else
            PCSrc = 0;
        RegRW = 0;   
        DataMemRW = 0;
        Mem_Alu = 0;
        
        if(state == sEXE)begin
            if(op == 4'b0000 || op == 4'b0001)//取数或加法
                RegRW = 1;
            else
                RegRW = 0;
            if(op == 4'b0011)//存数
                DataMemRW = 1;
             else
                DataMemRW = 0;
             if(op == 4'b0000)//取数
                Mem_Alu = 1;
             else
                Mem_Alu = 0;
        end
        
    end
    
    
endmodule

顶层模块

module Main(
    input clk,
    input rst,
    output [3:0]op,
    output [2:0]r1,
    output [2:0]r2,
    output [8:0]addr,
    output [11:0]imm,
    output [15:0]Regdata1,
    output [15:0]Regdata2,
    output [15:0]write_data
    );
    wire[15:0]newAddress,currentAddress,pc_address,
    Ins,extendImm,
    ALUA,ALUB,result,memData;
    wire PCWre,PCSrc,IRWre,RegRW,ALUSrcA,ALUSrcB,
    Mem_Alu,DataMemRW;
    wire[2:0]alu_op;
    
    PC pc(clk,rst,PCWre,newAddress,currentAddress);
    
    InsMemory insmemory(currentAddress,Ins);
    
    IR ir(clk,IRWre,Ins,op,r1,r2,addr,imm);
    
    RegFile regfile(clk,RegRW,r1,r2,write_data,Regdata1,Regdata2);
    
    SignZeroExtend signExtend(imm,extendImm);
    
    TempReg A(clk,ALUSrcA,Regdata1,ALUA);
    TempReg B(clk,ALUSrcB,Regdata2,ALUB);
    
    ALU alu(alu_op,ALUA,ALUB,result);
    
    DataMemory dataMemory(DataMemRW,addr,Regdata1,memData);
    
    Multiplexer16 mul1(Mem_Alu,memData,result,write_data);//用于选择输入RegFile的数据
    
    assign pc_address = currentAddress + 1;
    Multiplexer16 mu12(PCSrc,extendImm,pc_address,newAddress);//用于选择PC的newAddress
    
    ControlUnit cu(clk,rst,op,PCWre,PCSrc,IRWre,ALUSrcA,ALUSrcB,
    Mem_Alu,RegRW,DataMemRW,alu_op);
    
    
    
endmodule

测试模块

module Test();
    reg clk,rst;
    wire[3:0]op;
    wire[2:0]r1,r2;
    wire[8:0]addr;
    wire[11:0]imm;
    wire[15:0]Regdata1,Regdata2,write_data;
    
    Main main(clk,rst,op,r1,r2,addr,imm,Regdata1,Regdata2,write_data);
    initial begin
        clk = 0;rst=1;
        #40 $stop;
        
    end
    always #1 clk = ~clk;
endmodule

展示

在这里插入图片描述
状态0是取指阶段,状态1是译码阶段,状态2是执行阶段。下张图打错了,就不改了。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 15
    点赞
  • 103
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值