RISC-V处理器的设计与实现(二)—— CPU框架设计

目录

文章传送门

一、CPU和计算机的关系

二、CPU的工作流程

三、CPU的架构设计

1、取指阶段

2、译码阶段

3、执行阶段

四、仿真流程


文章目录

RISC-V处理器的设计与实现(一)—— 基本指令集_Patarw_Li的博客-CSDN博客

RISC-V处理器的设计与实现(二)—— CPU框架设计_Patarw_Li的博客-CSDN博客

RISC-V处理器的设计与实现(三)—— 上板验证_Patarw_Li的博客-CSDN博客

RISC-V处理器设计(四)—— Verilog 代码设计-CSDN博客 

RISC-V处理器设计(五)—— 在 RISC-V 处理器上运行 C 程序-CSDN博客 


前面我们选好了要实现的指令集,并且了解了每个指令的功能(传送门:RISC-V处理器的设计与实现(一)—— 基本指令集_Patarw_Li的博客-CSDN博客),接下来我们就可以开始设计cpu了。当然我们不可能一上来就写代码,首先我们要把cpu的结构、工作流程了解清楚,然后再开始代码的编写。

本项目的源码仓库:

cpu_prj: 一个基于RISC-V指令集的CPU实现

一、CPU和计算机的关系

说到计算机,那就不得不提大名鼎鼎的冯诺依曼了:

约翰·冯·诺依曼(John von Neumann,1903年12月28日-1957年2月8日),美籍匈牙利数学家,计算机科学家,物理学家,是20世纪最重要的数学家之一。冯·诺依曼是罗兰大学数学博士,是现代计算机,博弈论,核武器和生化武器等领域内的科学全才之一,被后人称为“现代计算机之父”、“博弈论之父”。

而现在的计算机大多都遵循冯诺依曼结构:

冯诺依曼结构包括如下4个部分: 

  • CPU,即中央处理器,是一台计算机的运算核心和控制核心。其功能主要是解释计算机指令以及处理计算机软件中的数据。CPU由运算器、控制器、寄存器、高速缓存及实现它们之间联系的数据、控制及状态的总线构成
  • 存储器,分为外存和内存, 用于存储数据(使用二进制方式存储)
  • 输入设备,用户给计算机发号施令的设备
  • 输出设备,计算机个用户汇报结果的设备

其中最核心的部分也就是CPU了,CPU又名中央处理器(Central Processing Unit,简称CPU),它由ALU(算术逻辑单元)和CU(控制单元)两部分组成:

  • ALU 算术逻辑单元(Arithmetic logical Unit):是中央处理器(CPU)的执行单元,是所有中央处理器的核心组成部分,由"And Gate"(与门) 和"Or Gate"(或门)构成的算术逻辑单元,主要功能是进行二位元的算术运算,如加减乘(不包括整数除法)。基本上,在所有现代CPU体系结构中,二进制都以补码的形式来表示。
  • CU 控制单元(Control Unit):负责程序的流程管理。控制单元是整个 CPU 的指挥控制中心,对协调整个计算机有序工作极为重要。

此外还包括一些寄存器,如PC(程序计数器) 、IR(指令寄存器)和一些通用寄存器等等。

二、CPU的工作流程

CPU执行分为5个阶段,取指阶段(IF)、译码阶段(ID)、执行阶段(EX)、访存阶段(MEM)、写回阶段(WB):

一、取指令阶段
取指令(Instruction Fetch,IF)阶段是根据PC的值,将一条指令从主存中取到指令寄存器的过程。程序计数器PC中的数值,用来指示当前指令在主存中的位置。当一条指令被取出后,PC中的数值将根据指令字长度而自动递增(如32位指令为PC+4)。

二、指令译码阶段
取出指令后,计算机进入指令译码(Instruction Decode,ID)阶段。

在指令译码阶段,指令译码器按照预定的指令格式,对取回的指令进行拆分和解释,识别区分出不同的指令类别以及各种获取操作数的方法。

三、执行指令阶段
在取指令和指令译码阶段之后,接着进入执行指令(Execute,EX)阶段。

此阶段的任务是完成指令所规定的各种操作,具体实现指令的功能。为此,CPU的不同部分被连接起来,以执行所需的操作。

四、访存取数阶段
根据指令需要,有可能要访问主存,读取操作数,这样就进入了访存取数(Memory,MEM)阶段。

此阶段的任务是:根据指令地址码,得到操作数在主存中的地址,并从主存中读取该操作数用于运算。

五、结果写回阶段
作为最后一个阶段,结果写回(Write Back,WB)阶段把执行指令阶段的运行结果数据“写回”。写回的地方一般是寄存器或者内存,其中写回寄存器的情况最多,方便之后的指令使用。

在有些情况下,结果数据也可被写入相对较慢、但较廉价且容量较大的主存。许多指令还会改变程序状态字寄存器中标志位的状态,这些标志位标识着不同的操作结果,可被用来影响程序的动作。

因为每个阶段的执行部件是分时复用的,所以可以用流水线的方式执行指令,下面是一个五级指令流水线:

三、CPU的架构设计

在了解上面这些内容后我们就可以开始CPU的框架设计了,为了简单,我们只设计三级流水线,写回和访存都放在执行阶段完成,下面是模块框架图:

1、取指阶段

取指阶段负责从rom中取出指令,传给译码阶段。其中pc模块输出需要取出的指令的地址pc_out,将指令地址传给rom后,rom寻址到对应指令再回传给if_id模块。if_id模块的作用是将指令和指令地址延后一拍传给译码模块ID_UNIT,延后一拍的目的是为了让系统以流水线的形式工作。

// 取指单元
module IF_UNIT(

    input   wire                     clk          ,
    input   wire                     rst_n        ,
    
    input   wire[2:0]                hold_flag_i  ,
    input   wire                     jump_flag    ,
    input   wire[`INST_REG_DATA]     jump_addr    ,
        
    output  wire[`INST_DATA_BUS]     ins_o        , // 指令
    output  wire[`INST_ADDR_BUS]     ins_addr_o   , // 指令地址
    
    output  wire[`INST_ADDR_BUS]     pc_o         , // 传给rom的指令地址
    input   wire[`INST_DATA_BUS]     ins_i          // rom根据地址读出来指令
    
    );
    
    wire[`INST_ADDR_BUS]       pc;
    assign pc_o = pc;
    
    
    // PC寄存器模块例化
    pc u_pc(
        .clk         (clk)  ,
        .rst_n       (rst_n),
        .hold_flag   (hold_flag_i),
        .jump_flag   (jump_flag),
        .jump_addr   (jump_addr),
        .pc_out      (pc)
    );
    
    // 指令寄存器模块例化
    if_id u_if_id(
        .clk         (clk),
        .rst_n       (rst_n),
        .hold_flag   (hold_flag_i),
        .ins_i       (ins_i), 
        .ins_addr_i  (pc),
        .ins_o       (ins_o), 
        .ins_addr_o  (ins_addr_o) 
    );
    
endmodule

2、译码阶段

译码阶段负责对指令进行译码。id模块从指令中读出寄存器写回地址rd,拼接立即数imm,从寄存器单元(RF_UNIT)中取出操作数R1、R2,然后将这些通过id_ex模块延后一拍传给执行模块EX_UNIT。

module ID_UNIT(

    input   wire                    clk            ,
    input   wire                    rst_n          ,
    
    input   wire                    hold_flag      ,
     
    //从IF模块传来的指令和指令地址
    input   wire[`INST_DATA_BUS]    ins_i          , 
    input   wire[`INST_ADDR_BUS]    ins_addr_i     , 
    
    // 传给RF模块的地址,用于读取数据
    output  wire[`INST_REG_ADDR]    reg1_rd_addr_o , 
    output  wire[`INST_REG_ADDR]    reg2_rd_addr_o ,
    
    // 根据传给RF模块地址读到的数据
    input   wire[`INST_REG_DATA]    reg1_rd_data_i , 
    input   wire[`INST_REG_DATA]    reg2_rd_data_i ,
    
    output  wire[`INST_DATA_BUS]    ins_o          , 
    output  wire[`INST_ADDR_BUS]    ins_addr_o     , 
    
    // 将读到的寄存器数据传给EX模块
    output  wire[`INST_REG_DATA]    reg1_rd_data_o , 
    output  wire[`INST_REG_DATA]    reg2_rd_data_o ,
    
    // 写寄存器地址
    output  wire[`INST_REG_ADDR]    reg_wr_addr_o  ,
    
    // 立即数
    output  wire[`INST_REG_DATA]    imm_o  
    );
    
    wire[`INST_REG_ADDR]    reg_wr_addr;
    wire[`INST_REG_DATA]    imm;
    
    // 指令译码模块例化
    id u_id(
        .clk            (clk),
        .rst_n          (rst_n),
        .ins_i          (ins_i), 
        .ins_addr_i     (ins_addr_i), 
        .reg1_rd_addr_o (reg1_rd_addr_o), 
        .reg2_rd_addr_o (reg2_rd_addr_o),
        .reg_wr_addr_o  (reg_wr_addr),
        .imm_o          (imm) 
    );
    
    // 将传给EX单元的内容打一拍
    id_ex u_id_ex(
        .clk            (clk),
        .rst_n          (rst_n),
        .hold_flag      (hold_flag),
        .ins_i          (ins_i), 
        .ins_addr_i     (ins_addr_i), 
        .reg1_rd_data_i (reg1_rd_data_i), 
        .reg2_rd_data_i (reg2_rd_data_i),
        .reg_wr_addr_i  (reg_wr_addr),
        .imm_i          (imm),
        .ins_o          (ins_o), 
        .ins_addr_o     (ins_addr_o), 
        .reg1_rd_data_o (reg1_rd_data_o), 
        .reg2_rd_data_o (reg2_rd_data_o),
        .reg_wr_addr_o  (reg_wr_addr_o),
        .imm_o          (imm_o)
    );
endmodule

3、执行阶段

执行阶段负责指令的执行、访存以及数据的回写。alu模块对传入的两个操作数进行计算,通过 alu_op_code来判断计算类型;cu负责发出各种控制信号,比如寄存器堆写使能信号、ram写使能信号、流水线暂停信号,等等;mul和div模块分别负责乘法和除法运算。

// 执行单元
module EX_UNIT(

    input   wire                    clk                 ,
    input   wire                    rst_n               ,
    
    input   wire[`INST_DATA_BUS]    ins_i               ,     
    input   wire[`INST_ADDR_BUS]    ins_addr_i          , 
    input   wire[6:0]               opcode_i            ,
    input   wire[2:0]               funct3_i            ,
    input   wire[6:0]               funct7_i            ,
    input   wire[`INST_REG_DATA]    imm_i               ,  
            
    input   wire[`INST_REG_DATA]    reg1_rd_data_i      , 
    input   wire[`INST_REG_DATA]    reg2_rd_data_i      ,
    input   wire[`INST_REG_ADDR]    reg_wr_addr_i       ,
     
    output  wire                    reg_wr_en_o         ,
    output  wire[`INST_REG_ADDR]    reg_wr_addr_o       ,
    output  wire[`INST_REG_DATA]    reg_wr_data_o       ,
    
    input   wire                    rib_hold_flag_i     ,
    output  wire                    jump_flag_o         ,
    output  wire[`INST_REG_DATA]    jump_addr_o         ,
    output  wire[2:0]               hold_flag_o         ,

    // 内存相关引脚(ram)
    input   wire[`INST_ADDR_BUS]    mem_rd_addr_i       ,
    input   wire[`INST_DATA_BUS]    mem_rd_data_i       ,
    output  wire                    mem_wr_rib_req_o    ,
    output  wire                    mem_wr_en_o         , 
    output  wire[`INST_ADDR_BUS]    mem_wr_addr_o       , 
    output  wire[`INST_DATA_BUS]    mem_wr_data_o       
    
    );
    
    wire[`INST_REG_DATA]     alu_data1;
    wire[`INST_REG_DATA]     alu_data2;
    wire[3:0]                alu_op_code;
    wire[`INST_REG_DATA]     alu_res;
    wire                     alu_zero_flag;
    wire                     alu_sign_flag;
    wire                     alu_overflow_flag;
     
    wire[2:0]                mul_op_code;
    wire[`INST_DB_REG_DATA]  mul_res;
    
    wire[2:0]                div_op_code;
    wire                     div_req;      
    wire                     div_busy;
    wire[`INST_REG_ADDR]     div_reg_wr_addr;
    wire                     div_res_ready;
    wire[`INST_REG_DATA]     div_res;
    
    reg [`INST_ADDR_BUS]     mem_rd_addr;
    
    // 内存读地址延迟一个时钟周期
    always @ (posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            mem_rd_addr <= `ZERO_WORD;
        end
        else begin
            mem_rd_addr <= mem_rd_addr_i;
        end
    end
    
    // 控制单元例化
    cu u_cu(
        .clk                 (clk),
        .rst_n               (rst_n),
        .ins_addr_i          (ins_addr_i), 
        .opcode_i            (opcode_i),
        .funct3_i            (funct3_i),
        .funct7_i            (funct7_i),
        .imm_i               (imm_i),  
        .alu_res_i           (alu_res),
        .alu_zero_flag_i     (alu_zero_flag),
        .alu_sign_flag_i     (alu_sign_flag),
        .alu_overflow_flag_i (alu_overflow_flag),
        .alu_op_code_o       (alu_op_code),
        .alu_data1_o         (alu_data1), 
        .alu_data2_o         (alu_data2),
        .mul_res_i           (mul_res),
        .mul_op_code_o       (mul_op_code),
        .div_res_i           (div_res),
        .div_busy_i          (div_busy), 
        .div_res_ready_i     (div_res_ready), 
        .div_reg_wr_addr_i   (div_reg_wr_addr),
        .div_req_o           (div_req), 
        .div_op_code_o       (div_op_code),
        .rib_hold_flag_i     (rib_hold_flag_i),          
        .jump_flag_o         (jump_flag_o),
        .jump_addr_o         (jump_addr_o),        
        .hold_flag_o         (hold_flag_o),
        .reg1_rd_data_i      (reg1_rd_data_i), 
        .reg2_rd_data_i      (reg2_rd_data_i),
        .reg_wr_addr_i       (reg_wr_addr_i),
        .reg_wr_en_o         (reg_wr_en_o),
        .reg_wr_addr_o       (reg_wr_addr_o),
        .reg_wr_data_o       (reg_wr_data_o),
        .mem_rd_addr_i       (mem_rd_addr),
        .mem_rd_data_i       (mem_rd_data_i),
        .mem_wr_rib_req_o    (mem_wr_rib_req_o),
        .mem_wr_en_o         (mem_wr_en_o), 
        .mem_wr_addr_o       (mem_wr_addr_o), 
        .mem_wr_data_o       (mem_wr_data_o)
    );
    
    // alu运算单元例化
    alu u_alu(
        .alu_data1_i         (alu_data1), 
        .alu_data2_i         (alu_data2),
        .alu_op_code_i       (alu_op_code),
        .alu_res_o           (alu_res),
        .alu_zero_flag_o     (alu_zero_flag),
        .alu_sign_flag_o     (alu_sign_flag),
        .alu_overflow_flag_o (alu_overflow_flag)
    );
    
    // 乘法单元例化
    mul u_mul(
        .mul_data1_i         (reg1_rd_data_i), 
        .mul_data2_i         (reg2_rd_data_i),
        .mul_op_code_i       (mul_op_code),
        .mul_res_o           (mul_res)
    );
    
    // 除法单元例化
    div u_div(
        .clk                 (clk),
        .rst_n               (rst_n),
        .div_data1_i         (reg1_rd_data_i), 
        .div_data2_i         (reg2_rd_data_i),
        .div_op_code_i       (div_op_code),
        .div_req_i           (div_req), 
        .div_reg_wr_addr_i   (reg_wr_addr_i),
        .div_reg_wr_addr_o   (div_reg_wr_addr),
        .div_busy_o          (div_busy), 
        .div_res_ready_o     (div_res_ready), 
        .div_res_o           (div_res)  
    );
    
endmodule

四、上板测试

本项目的 cpu 目前实现了 RV32I 和 RV32M 扩展,目前可以跑一些基本的c语言代码。

如何编译和测试请参考我的这篇博客:

开发一个RISC-V上的操作系统(一)—— 环境搭建_risc v 开发环境_Patarw_Li的博客-CSDN博客

如果遇到问题也欢迎加群 892873718 交流~ 

  • 17
    点赞
  • 89
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 香山开源高性能risc-v处理器设计实现 pdf 是一份介绍risc-v处理器设计实现的文档。risc-v是一种基于精简指令集的处理器架构,因其简洁、开放、可定制的特点,受到了广泛关注。 该文档详细介绍了如何在FPGA(现场可编程门阵列)上实现risc-v处理器。作者分享了开发处理器的具体步骤、设计方案、软件支持等方面的知识。并且,该处理器的性能也在文档中详细评估。 该处理器在性能、功耗等方面有着不俗表现。其主频可以达到400MHz以上,实现了乘-累加指令,并且具有64位寄存器和32个寄存器,支持RV64I标准指令集,内存延迟很低,具有较好的实时性能。 总之,香山开源高性能risc-v处理器设计实现 pdf是一份非常值得阅读的文档,其中对risc-v处理器设计实现有着详细的介绍,可以帮助人们了解risc-v处理器的优势和不足,为相关领域的开发提供指导。 ### 回答2: 《香山开源高性能risc-v处理器设计实现》是一本介绍如何设计实现RISC-V处理器的书籍,也是一本介绍RISC-V处理器架构的入门读物。该书深入浅出地介绍了RISC-V架构和处理器设计的基本知识,并通过实例详细地述说了如何基于该架构,设计实现一个高性能的RISC-V处理器。 该书的作者陈海波教授是一位专业的计算机架构工程师,他在书中将自己多年来的实践经验与理论知识完美结合,将复杂的概念以通俗易懂的方式呈现给读者。全书以RISC-V指令集架构、CPU内部运行机制、核心子系统设计等方面为主线,详细地介绍了处理器设计流程和实现细节。最后以在FPGA上的逻辑仿真和运行测试为实例,让读者真正了解该处理器的可靠性和高性能。 通过学习《香山开源高性能risc-v处理器设计实现》这本书,读者可以深入学习RISC-V处理器架构以及处理器设计方面的知识。不仅可以对计算机组成原理和计算机系统结构有更深入的理解,还可以掌握实际的设计开发技巧。对于从事处理器设计、嵌入式系统设计等领域的专业人员,是一本不可多得的参考书籍。 ### 回答3: 《香山开源高性能risc-v处理器设计实现》是一本介绍RISC-V处理器架构的书籍,该处理器架构是一个基于精简指令集(RISC)的开源处理器架构。本书主要介绍了香山开源处理器设计实现,是一本深入学习RISC-V架构的重要参考书。 该书共分为八章,首先介绍了处理器的基本概念和RISC-V处理器架构的特点。接着深入分析了RISC-V处理器的指令集和管道,讲解了指令集概述、流水线架构、指令编码等内容。紧接着,本书介绍了一款基于RISC-V架构的香山开源处理器,详细介绍了处理器的数据通路、控制单元、存储结构等模块的实现原理。 在完成处理器架构描述之后,本书详细介绍了基于Vivado实现处理器设计和仿真调试的方法。通过实际例子的讲解,读者可以深入了解如何通过Vivado进行处理器设计和仿真调试。 该书最后介绍了一些关于RISC-V处理器架构的扩展和应用的内容,如在处理器架构扩展方面的内容,以及如何在RISC-V处理器架构上实现操作系统和应用程序的开发。 总之,《香山开源高性能risc-v处理器设计实现》是一本详细介绍RISC-V处理器架构和实现方法的书籍,对于学习处理器架构和实现的读者是一本不可多得的参考书。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值