IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> RISC-V CPU设计(三)---多周期CPU的设计与实现 -> 正文阅读

[嵌入式]RISC-V CPU设计(三)---多周期CPU的设计与实现

基本情况

本多周期CPU支持RV32I指令集(fence,ecall,ebreak除外),已通过部分指令的测试,如代码有bug,欢迎指出

模块划分

代码将CPU划分为以下几个模块:
1.控制单元:ControlUnit
用于产生控制信号,是CPU的大脑,指挥中枢。
2.分支决策单元:BranchUnit
用于决定B型指令是否发生跳转
3.立即数单元:ImmUnit
用于从指令中解析出立即数.
4.寄存器堆:RegisterFile
RISC-V的32个寄存器,其中x0寄存器恒为0,不可更改
5.指令存储器:InstrMem
用于存储指令,目前仅支持32位指令,不支持16位指令,且地址是4字节对齐的。
6.数据存储器:DataMem
数据存储器,用于存储数据,可进行字、半字、字节的读写。
7.Data_Ext
用于load指令,从读出的字中获取需要的部分,并进行符号/无符号扩展。例如LH,LBU指令选取哪个半字、哪个字节,以及如何扩展为32bit。
8.PC生成单元:NPC_Generator
根据Jal,Jalr以及Branch生成下一条指令的地址(PCF),若上述三个信号均为无效电平,则更新为PCF+4
9.计算部件:ALU
用于算数逻辑运算。

代码

控制单元

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2022/03/15 18:13:29
// Design Name: 
// Module Name: ControlUnit
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//
`include"Parameters.v"
import Params::*;

module ControlUnit(
input logic [6:0] Op,
input logic [2:0] Fn3,
input logic [6:0] Fn7,
output logic JalD,                      //是否为Jal指令
output logic JalrD,                     //是否是Jalr指令
output LoadType RegWriteD,              //LOAD指令字节选取(LW,LH,LB,...)
output logic MemToRegD,                 //写入寄存器的值是否来自MEM
output logic [3:0] MemWriteD,           //写MEM时字节选中信号,S类型指令
output logic LoadNpcD,                  //MEM阶段是否计算PC+4,用于Jal和Jalr指令
output BType BranchTypeD,          //分支指令类型,BEQ,BNE,...
output AluOp AluControlD,          //EXE阶段ALU控制信号,进行何种运算
output logic [1:0] AluSrc2D,             //第二个源操作数的来源
output logic AluSrc1D,                   //第一个源操作数的来源,rs1或者pc
output Type ImmType               //立即数类型,不同类型解析不同
    );

//jal,jalr
assign JalD=(Op==7'b1101111)?1'b1:1'b0;                   //是否为Jal指令
assign JalrD=(Op==7'b1100111)?1'b1:1'b0;                  //是否为jalr指令
//RegWriteD
always_comb
begin
    if(Op==7'b0000011)                    //是load指令
    begin
        case(Fn3)
            3'b000:RegWriteD=LB; //LB
            3'b001:RegWriteD=LH; //LH
            3'b010:RegWriteD=LW; //LW
            3'b100:RegWriteD=LBU; //LBU
            3'b101:RegWriteD=LHU; //LHU
            default:RegWriteD=NOREGWRITE;                        //出错,不写寄存器
        endcase
    end
    else if(Op==7'b0010011||Op==7'b0110011||Op==7'b0110111||Op==7'b0010111||Op==7'b1101111||Op==7'b1100111)
    begin
        RegWriteD=LW;             //I型指令(寄存器-立即数指令)、R型指令、U型指令(LUI,AUIPC),J型指令(JAL)和JALR指令,写寄存器
    end
    else                           //B型,S型指令,不写寄存器
    begin
        RegWriteD=NOREGWRITE;
    end
end
//MemToRegD
always_comb
begin
    if(Op==7'b0000011)           //是load指令
        MemToRegD=1;
    else                         //其他指令数据均不来自于MEM
        MemToRegD=0;           
end
//MemWriteD
always_comb
begin
    if(Op==7'b0100011)             //S型指令,写MEM
        case(Fn3)
           3'b000:MemWriteD=4'b0001;    //SB
           3'b001:MemWriteD=4'b0011;    //SH
           3'b010:MemWriteD=4'b1111;    //SW
           default:MemWriteD=4'b0000;
        endcase
    else
        MemWriteD=4'b0000;
end
//LoadNpcD
assign LoadNpcD=(JalD|JalrD)?1'b1:1'b0;                //只有Jal指令和Jalr指令时会计算PC+4并存入Reg[Rd]
//BranchTypeD
always_comb
begin
    if(Op==7'b1100011)                     //如果是B型指令(条件分支)
        case(Fn3)
           3'b000:BranchTypeD=BEQ;     //BEQ
           3'b001:BranchTypeD=BNE;     //BNE
           3'b100:BranchTypeD=BLT;     //BLT
           3'b101:BranchTypeD=BGE;     //BGE
           3'b110:BranchTypeD=BLTU;     //BLTU
           3'b111:BranchTypeD=BGEU;     //BGEU
           default:BranchTypeD=NOBRANCH;
        endcase
    else
        BranchTypeD=NOBRANCH;
end
//AluControlD
always_comb
begin
    case(Op)
        7'b0000011:AluControlD=ADD;       //LOAD指令,计算地址,ADD
        7'b0100011:AluControlD=ADD;       //STORE指令,计算地址,ADD
        7'b0110111:AluControlD=LUI;       //LUI指令,保持立即数不变
        7'b0010111:AluControlD=ADD;       //AUIPC指令,Reg[rs1]+Imm,ADD
        7'b1100011:AluControlD=ADD;       //B型条件分支指令,不使用ALU,dont care(分支跳转地址计算在ID阶段完成)
        7'b1101111:AluControlD=ADD;       //jal指令,未用到ALU(地址计算在ID阶段完成)
        7'b1100111:AluControlD=ADD;       //jalr指令,计算跳转地址(Reg[rs1]+Imm)&~1,ADD
        7'b0110011:                         //R型指令
        begin
            case(Fn3)
                3'b000:if(Fn7[5]==0)
                           AluControlD=ADD;
                       else
                           AluControlD=SUB;
                3'b001:AluControlD=SLL;
                3'b010:AluControlD=SLT;
                3'b011:AluControlD=SLTU;
                3'b100:AluControlD=XOR;
                3'b101:if(Fn7[5]==0)
                           AluControlD=SRL;
                       else
                           AluControlD=SRA;
                3'b110:AluControlD=OR;
                3'b111:AluControlD=AND;
                default:AluControlD=ADD;
            endcase
        end
        7'b0010011:                         //I型指令(寄存器-立即数和移位指令)
        begin
            case(Fn3)
                3'b000:AluControlD=ADD;
                3'b010:AluControlD=SLT;
                3'b011:AluControlD=SLTU;
                3'b100:AluControlD=XOR;
                3'b110:AluControlD=OR;
                3'b111:AluControlD=AND;
                3'b001:AluControlD=SLL;
                3'b101:if(Fn7[5]==0)
                            AluControlD=SRL;
                       else
                            AluControlD=SRA;
                default:AluControlD=ADD;
            endcase
        end
        default:AluControlD=ADD;
    endcase
end

//AluSrc1D,PC or 寄存器rs1
always_comb
if(Op==7'b0010111)                   //AUIPC指令,第一个源操作数来自PC
    AluSrc1D=1;
else
    AluSrc1D=0;
//AluSrc2D
always_comb
begin
    if(Op==7'b0010011&&(Fn3==3'b001||Fn3==3'b101))                  //移位指令
        AluSrc2D=2'b00;                  //来自rs2
    else if(Op==7'b1100011||Op==7'b0110011)           //R型指令或者B型指令
        AluSrc2D=2'b01;                 //来自Reg[rs2]
    else                                //其他指令
        AluSrc2D=2'b10;                 //来自立即数
end
//ImmTypeD
always_comb
begin
    case(Op)
        7'b0110011:ImmType=RTYPE;
        7'b0010011:ImmType=ITYPE;
        7'b0000011:ImmType=ITYPE;
        7'b1100111:ImmType=ITYPE;
        7'b1100011:ImmType=BTYPE;
        7'b0100011:ImmType=STYPE;
        7'b1101111:ImmType=JTYPE;
        7'b0110111:ImmType=UTYPE;
        7'b0010111:ImmType=UTYPE;
        default:ImmType=RTYPE;
    endcase
end

endmodule

计算单元

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2022/03/16 16:43:50
// Design Name: 
// Module Name: ALU
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//
import Params::*;
`include "Parameters.v"
module ALU(
input logic [31:0] Operand1,
input logic [31:0] Operand2,
input AluOp AluControl,
output logic [31:0] AluOut
    );

always_comb
begin
    case(AluControl)
       SLL:AluOut=Operand1<<(Operand2[4:0]);               //逻辑左移
       SRL:AluOut=Operand1>>(Operand2[4:0]);               //逻辑右移
       SRA:AluOut=$signed(Operand1)>>>(Operand2[4:0]);              //算术右移
       ADD:AluOut=Operand1+Operand2;                       //加
       SUB:AluOut=Operand1-Operand2;                       //减
       XOR:AluOut=Operand1^Operand2;                       //异或
       OR:AluOut=Operand1|Operand2;                         //或
       AND:AluOut=Operand1&Operand2;                        //与
       SLT:AluOut=($signed(Operand1)<$signed(Operand2))?32'd1:32'd0;            //小于置位
       SLTU:AluOut=(Operand1<Operand2)?32'd1:32'd0;                             //无符号小于置位
       LUI:AluOut=Operand2;                                                     //LUI指令
       default:AluOut=0;
    endcase
end
endmodule
//ALUContrl
/*
    `define SLL  4'd0
    `define SRL  4'd1
    `define SRA  4'd2
    `define ADD  4'd3
    `define SUB  4'd4
    `define XOR  4'd5
    `define OR  4'd6
    `define AND  4'd7
    `define SLT  4'd8
    `define SLTU  4'd9
    `define LUI  4'd10
*/

立即数生成单元

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2022/03/16 15:09:41
// Design Name: 
// Module Name: ImmUnit
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//
import Params::*;
`include "Parameters.v"

module ImmUnit(
input Type ImmType,
input logic [31:0] In,
output logic [31:0] Out
    );
always_comb
begin
    case(ImmType)
        RTYPE:Out=32'd0;
        ITYPE:Out={{20{In[31]}},In[31:20]};                                            //有符号扩展
        UTYPE:Out={In[31:12],12'd0};                                                   //低12位添0
        BTYPE:Out={{19{In[31]}},In[31],In[7],In[30:25],In[11:8],1'b0};                 //左移1位,符号扩展
        JTYPE:Out={{11{In[31]}},In[31],In[19:12],In[20],In[30:21],1'b0};               //左移1位,符号扩展
        STYPE:Out={{20{In[31]}},In[31:25],In[11:7]};                                   //符号扩展      
        default:Out=32'd0;
    endcase
end
endmodule

分支决策单元

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2022/03/16 14:58:00
// Design Name: 
// Module Name: BranchUnit
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//
`include "Parameters.v"
import Params::*;

module BranchUnit(
input logic [31:0] Reg1,               //第一个源操作数
input logic [31:0] Reg2,               //第二个源操作数
input BType BrType,              //条件分支指令类型
output logic BranchE                   //是否跳转
    );
always_comb 
begin
    case(BrType)
        BEQ:if(Reg1==Reg2)
                 BranchE=1;
             else
                 BranchE=0;
        BNE:if(Reg1!=Reg2)
                 BranchE=1;
             else
                 BranchE=0;
        BLT:if($signed(Reg1)<$signed(Reg1))            //有符号数比较
                 BranchE=1;
             else
                 BranchE=0;
        BLTU:if(Reg1<Reg2)
                 BranchE=1;
              else
                 BranchE=0;
        BGE:if($signed(Reg1)>=$signed(Reg2))          //有符号数比较
                 BranchE=1;
             else
                 BranchE=0;
        BGEU:if(Reg1>=Reg2)
                 BranchE=1;
              else
                 BranchE=0;
        default:BranchE=0;
    endcase
end
endmodule

寄存器文件

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2022/03/16 17:38:45
// Design Name: 
// Module Name: RegisterFile
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module RegisterFile(
input logic clk,
input logic [4:0] RS1,                 //要读的寄存器编号
input logic [4:0] RS2,                 //要读的寄存器编号
output logic [31:0] RegOut1,           //读出内容:Reg[rs1]
output logic [31:0] RegOut2,           //读出内容:Reg[rs2]
input logic [31:0] WD,                 //要写入寄存器的数据
input logic [4:0] RD,                  //写寄存器编号
input logic WE                         //写使能
    );

logic [31:0] RegFile [0:31];
//初始化
initial 
begin
    for(int i=0;i<32;i++)
        RegFile[i]=0;
end
//下降沿写入数据
always_ff@(negedge clk)
begin
    if(WE)
    begin
        if(RD!=0)                       //第0个寄存器不可写
            RegFile[RD]<=WD;
    end
end
//读数据
always_comb
begin
    RegOut1=RegFile[RS1];
    RegOut2=RegFile[RS2];
end
endmodule

数据存储器

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2022/03/16 20:20:04
// Design Name: 
// Module Name: DataMem
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module DataMem(
input logic clk,
input logic [31:0] A,                  //地址
input logic [31:0] WD,                 //要写入的数据
input logic [3:0] WE,                  //写使能(一个字节一位) 
output logic [31:0] RD                 //读出的数据
    );
parameter  N = 4096;
logic [31:0] DMEM [0:N-1];             //数据存储器
//初始化
initial begin
    for(int i=0;i<N;i++)
        DMEM[i]=i;
end
//读数据
assign RD=DMEM[A[31:2]];               //数据读出
//写数据,下降沿写入
always_ff@(negedge clk)                 
begin
    case(WE)                          //根据写使能信号将数据写入DMEM
        4'b0001:DMEM[A[31:2]][7:0]<=WD[7:0];
        4'b0011:DMEM[A[31:2]][15:0]<=WD[15:0];
        4'b1111:DMEM[A[31:2]]<=WD;
        default:;
    endcase
end

endmodule

指令存储器

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2022/03/16 20:15:48
// Design Name: 
// Module Name: InstrMem
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module InstrMem(
input logic [31:0] InstrAddr,                //指令地址,4字节对齐
output logic [31:0] Instr                    //读出的指令
    );
parameter  N = 64;
logic [31:0] IMEM [0:N-1];                   //指令存储器
//
initial begin
    IMEM[0]=32'h00410093;                           //指令初始化
    IMEM[1]=32'h00102423;
    IMEM[2]=32'h0040a283;
    IMEM[3]=32'h0000c437;
    IMEM[4]=32'h0000c317;
    IMEM[5]=32'h00508133;
    IMEM[6]=32'h00508463;
    IMEM[7]=32'h005080b3;
    IMEM[8]=32'h00c000ef;
    IMEM[9]=32'h005080b3;
    IMEM[10]=32'h005080b3;
    IMEM[11]=32'h40508433;
    IMEM[12]=32'h00241513;
    IMEM[13]=32'h40155633;
    IMEM[14]=32'h401003b3;
    IMEM[15]=32'h4013d393;
    IMEM[16]=32'h04428867;
    IMEM[17]=32'h001080b3;
    IMEM[18]=32'h00187813;
end
//读指令
assign Instr=IMEM[InstrAddr[31:2]];

endmodule

PC生成单元

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2022/03/16 20:32:07
// Design Name: 
// Module Name: NPC_Generator
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module NPC_Generator(
input logic Jal,
input logic Jalr,
input logic Branch,
input logic [31:0] JalT,
input logic [31:0] JalrT,
input logic [31:0] BrT,
input logic [31:0] PC,
output logic [31:0] NPC
    );

always_comb
begin
    if(Jalr)
        NPC=JalrT;
    else if(Branch)
        NPC=BrT;
    else if(Jal)               //Jal优先级低于Jalr和Branch,因为在五级流水线中,Jal更新地址发生在ID阶段,而后者发生在EXE阶段,同时检测到时,后两条指令时间上更早
        NPC=JalT;
    else
        NPC=PC+4;
end

endmodule

Data_Ext单元

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2022/03/16 15:49:39
// Design Name: 
// Module Name: Data_Ext
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//
`include "Parameters.v"
import Params::*;

module Data_Ext(
input logic [1:0] LoadByteSelect,
input LoadType RegWrite,
input logic [31:0] In,
output logic [31:0] Out
    );
//RegWrite决定读取的字还是半字还是字节
//LoadByteSelect决定读取哪个半字、哪个字节
always_comb
begin
    case(RegWrite)
        LW:Out=In;
        LH:begin
            case(LoadByteSelect)
               2'b00:Out={{16{In[15]}},In[15:0]};
               2'b01:Out={{16{In[23]}},In[23:8]};
               2'b10:Out={{16{In[31]}},In[31:16]};
               2'b11:Out=0;                                     //错误
            endcase
        end
        LHU:begin
            case(LoadByteSelect)
               2'b00:Out={16'd0,In[15:0]};
               2'b01:Out={16'd0,In[23:8]};
               2'b10:Out={16'd0,In[31:16]};
               2'b11:Out=0;                              //错误
            endcase
        end
        LB:begin
            case(LoadByteSelect)
               2'b00:Out={{24{In[7]}},In[7:0]};
               2'b01:Out={{24{In[15]}},In[15:8]};
               2'b10:Out={{24{In[23]}},In[23:16]};
               2'b11:Out={{24{In[31]}},In[31:24]};
            endcase
        end
        LBU:begin
            case(LoadByteSelect)
               2'b00:Out={24'd0,In[7:0]};
               2'b01:Out={24'd0,In[15:8]};
               2'b10:Out={24'd0,In[23:16]};
               2'b11:Out={24'd0,In[31:24]};
            endcase
        end
        default:Out=In;
    endcase
end
endmodule

顶层模块

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2022/03/17 09:43:41
// Design Name: 
// Module Name: MC_RV32Core
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//
`include "Parameters.v"
import Params::*;

module MC_RV32Core(
input logic clk,
input logic rst_n
    );
//状态机
typedef enum bit [2:0] { 
    IDLE,
    IF,ID,EXE,MEM,WB
} State;
State cur_state,next_state;              //状态机
//ID
logic [4:0] RS1;              //第一个源操作数的寄存器编号
logic [4:0] RS2;              //第二个源操作数的寄存器编号
logic [4:0] RD;               //目的寄存器编号
logic [31:0] Imm;             //解析得到的立即数
logic [6:0] Op;               //操作码
logic [2:0] Fn3;              //功能字段
logic [6:0] Fn7;              //功能字段
logic Jal;                    //Jal指令
logic Jalr;                   //Jalr指令
LoadType RegWrite;         //数据选取
logic MemToReg;               //写寄存器的数据是否来自MEM
logic [3:0] MemWrite;         //写数据存储器
logic LoadNpc;                //是否计算PCF+4
BType BranchType;       //条件分支指令类型
AluOp AluControl;       //ALU控制信号
logic AluSrc1;                //第一个源操作数来源
logic [1:0] AluSrc2;          //第二个源操作数来源
Type ImmType;          //立即数类型
logic [31:0] RegOut1;         //寄存器读出值
logic [31:0] RegOut2;         //寄存器读出值
logic [31:0] JalT;            //Jal跳转地址
//IF
logic [31:0] PCF;             //当前PC地址,根据PCF的值读取指令
logic [31:0]Instr;            //读出的指令
logic [31:0] NPC;             //下一条指令的地址
//EXE
logic [31:0] Operand1;              //ALU源操作数1
logic [31:0] Operand2;              //ALU源操作数2
logic [31:0] AluOut;                //ALU输出
logic [31:0] BrT;                   //条件分支跳转地址
logic [31:0] JalrT;                 //Jalr跳转地址
//MEM
logic [31:0] StoreData;             //要写入存储器的数据
logic [31:0] DM_RD;                 //数据存储器读出数据
logic [31:0] Result;                //要写入寄存器堆的数据,或来自Alu,或来自PCF+4,由LoadNpc决定
//WB
logic [31:0] RegWriteData;          //要写入寄存器的数据,或来自于DMEM,或来自于其他
logic [31:0] DM_RD_EXT;             //字节选择后的DMEM读出数据
logic RegWriteEn;                   //是否写寄存器堆
//解析Instr的各个字段,包括RS1,RS2,RD,Op,Fn3,Fn7
assign RS1=Instr[19:15];
assign RS2=Instr[24:20];
assign RD=Instr[11:7];
assign Op=Instr[6:0];
assign Fn3=Instr[14:12];
assign Fn7=Instr[31:25];
//RegWriteEn,寄存器写使能信号
//是否写寄存器堆,仅在WB阶段写    
always_comb 
begin
    if(cur_state==WB)                     //仅在WB阶段写寄存器
    begin
        if(RegWrite==NOREGWRITE)
             RegWriteEn=0;
        else
             RegWriteEn=1;
    end
    else
        RegWriteEn=0;
end    
//PCF
always_ff@(posedge clk,negedge rst_n)
if(~rst_n)
    PCF<=0;
else if(cur_state==WB)                                //地址均在WB阶段更新
    PCF<=NPC;
//Operand1,Operand2
always_comb
begin
    if(AluSrc1==1'b1)
        Operand1=PCF;
    else
        Operand1=RegOut1;
end
always_comb
begin
    if(AluSrc2==2'b00)                       //移位指令
        Operand2=RS2;
    else if(AluSrc2==2'b01)                  //R型和B型指令
        Operand2=RegOut2;
    else                                     //其他,来自立即数
        Operand2=Imm; 
end
//StoreData
assign StoreData=RegOut2;                     //仅在指令为S型指令时有效,其值为Reg[rs2]
//Result
always_comb
begin
    if(LoadNpc)                            //jal,jalr指令,将PCF+4写入Reg[rd]
        Result=PCF+4;
    else
        Result=AluOut;
end
//RegWriteData
always_comb
begin
    if(MemToReg)
         RegWriteData=DM_RD_EXT;
    else
         RegWriteData=Result;
end
//JalT,JalrT,BrT
assign JalT=Imm+PCF;               //加法部件计算得到
assign JalrT=AluOut;               //ALU计算得到
assign BrT=Imm+PCF;                //加法部件计算得到
//三段式状态机
always_ff@(posedge clk,negedge rst_n)
if(~rst_n)
    cur_state<=IDLE;
else
    cur_state<=next_state;
//
always_comb begin
    case(cur_state)
        IDLE:if(~rst_n)
                 next_state=IDLE;
             else
                 next_state=IF;
        IF:next_state=ID;
        ID:next_state=EXE;
        EXE:next_state=MEM;
        MEM:next_state=WB;
        WB:next_state=IF;
        default:next_state=IDLE;
    endcase
end

//模块例化
//控制单元
ControlUnit U1(
.Op(Op),
.Fn3(Fn3),
.Fn7(Fn7),
.JalD(Jal),                      //是否为Jal指令
.JalrD(Jalr),                     //是否是Jalr指令
.RegWriteD(RegWrite),           //LOAD指令字节选取(LW,LH,LB,...)
.MemToRegD(MemToReg),                 //写入寄存器的值是否来自MEM
.MemWriteD(MemWrite),           //写MEM时字节选中信号,S类型指令
.LoadNpcD(LoadNpc),                  //MEM阶段是否计算PC+4,用于Jal和Jalr指令
.BranchTypeD(BranchType),          //分支指令类型,BEQ,BNE,...
.AluControlD(AluControl),          //EXE阶段ALU控制信号,进行何种运算
.AluSrc2D(AluSrc2),             //第二个源操作数的来源
.AluSrc1D(AluSrc1),                   //第一个源操作数的来源,rs1或者pc
.ImmType(ImmType)               //立即数类型,不同类型解析不同
    );
//ALU
ALU U2(
.Operand1(Operand1),
.Operand2(Operand2),
.AluControl(AluControl),
.AluOut(AluOut)
    );
//BranchUnit
BranchUnit U3(
.Reg1(Operand1),               //第一个源操作数
.Reg2(Operand2),               //第二个源操作数
.BrType(BranchType),              //条件分支指令类型
.BranchE(Branch)                   //是否跳转
    );
//数据存储器
DataMem U4(
.clk(clk),
.A(AluOut),                     //地址
.WD(StoreData),                 //要写入的数据
.WE(MemWrite),                          //写使能(一个字节一位) 
.RD(DM_RD)                      //读出的数据
);
//数据选取单元
Data_Ext U5(
.LoadByteSelect(AluOut[1:0]),
.RegWrite(RegWrite),
.In(DM_RD),
.Out(DM_RD_EXT)
    );
//立即数单元
ImmUnit U6(
.ImmType(ImmType),               //指令中立即数的类型
.In(Instr),                      //输入指令
.Out(Imm)                        //输出解析得到的立即数
    );
//指令存储器
InstrMem U7(
.InstrAddr(PCF),                //指令地址,4字节对齐
.Instr(Instr)                    //读出的指令
    );
//PC生成单元
NPC_Generator U8(
.Jal(Jal),
.Jalr(Jalr),
.Branch(Branch),
.JalT(JalT),
.JalrT(JalrT),
.BrT(BrT),
.PC(PCF),
.NPC(NPC)
);
//寄存器堆
RegisterFile U9(
.clk(clk),
.RS1(RS1),                 //要读的寄存器编号
.RS2(RS2),                 //要读的寄存器编号
.RegOut1(RegOut1),           //读出内容:Reg[rs1]
.RegOut2(RegOut2),           //读出内容:Reg[rs2]
.WD(RegWriteData),                 //要写入寄存器的数据
.RD(RD),                  //写寄存器编号
.WE(RegWriteEn)                         //写使能
);
endmodule

完整工程见gitee
指令存储器中的测试指令(涵盖了所有类型,包括R型,I型(移位、寄存器计立即数和load),U型(auipc和lui),J型(jal),B型,S型),其相应的汇编代码如下所示(这些指令已经通过测试),读者可以根据汇编代码验证CPU的正确性,同时加深对CPU执行指令的理解(更多的指令测试还未进行,如发现有运行错误的指令,欢迎提出
在这里插入图片描述

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-03-21 21:07:25  更:2022-03-21 21:10:01 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 6:29:09-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码