概述
RISC-V加法指令的实现(Ⅰ)
文章目录
- RISC-V加法指令的实现(Ⅰ)
- 前言
- 一、RISC-V简介
- 二、指令实现的前期准备
- 1.指令
- 2.ADD指令和ADDI指令
- 3.三级流水线结构
- 4.一个需要注意的点
- 5.再来一个需要注意的点
- 6.环境搭建
- 总结
前言
通过verilog来搭建一个CPU的想法由来已久了,一方面是为了增加自己为数不多的项目经历,另一方面是真的想弄明白,CPU内部究竟到底是怎么运行的。
今天就正式开始了,此工程很大,更新进度取决于自身学习情况以及别的up主的更新进程;可能会很慢,也可能哪天夭折了;虽然路途很遥远,但是总要迈出第一步吧~能学多少是多少了哈哈。
本文首发于公众号:FPGA学习者,关注公众号,获取更多资料与内容。
主要参考B站:@外瑞罗格
一、RISC-V简介
简介嘛,为了节省时间,那我就不按照官方表述来介绍了;
先来看一个指令集的概念,顾名思义,是一组指令的集合,指令是处理器进行操作的最小单元。区分CPU的标准主要就是指令集架构。
指令集架构主要分为复杂指令集(CISC)和精简指令集(RISC)。
CISC | Complex Instruction Set Computer |
---|---|
RISC | Reduced Instruction Set Computer |
RISC-V就是基于精简指令集的一种处理器架构,2010年发明至今已经更新到第五代,最大的特点在于开源。(当然,也有其他的开源架构,比如MIPS等)详细介绍可参阅书籍《手把手教你设计CPU——RISC-V处理器篇》,该书籍电子版获取方式在文末给出。
不说废话了,重点关注怎么能够上手实现一些基本的功能吧。
二、指令实现的前期准备
1.指令
指令包括R类、I类、S类、SB类、U类、UJ类等等,主要区别在于编码方式;RISC-V使用的都是32位指令,所以我们实现的是一个32位处理器。(多少位处理器的区别就在于指令是多少位的)。
今天先不涉及那么多,先看R类和I类指令:对于R类指令:
(6 0)操作码:opcode
(11 7)目的寄存器
(14 12)func3
(19 15)源寄存器1
(24 20)源寄存器2
(31 24)func7
对于I类指令(即带有立即数的指令):
(6 0)操作码:opcode
(11 7)目的寄存器
(14 12)func3
(19 15)源寄存器1
(31 20)立即数
func为功能码,主要用来判断功能。
2.ADD指令和ADDI指令
ADDI rd rs1 imm;
ADDI指令实现立即数+rs1寄存器中的内容,存放到rd寄存器中。
ADD rd rs2 rs1;
ADD指令实现rs1寄存器中的内容+rs2寄存器中的内容,存放到rd寄存器中。 (rs:register source,源寄存器;rd:register destination,目的寄存器)。
对于I类指令的立即数,运算之前需要对其进行位扩展,按照有符号数进行扩展至32位:
3.三级流水线结构
三级流水线结构指只需要三个系统时钟,便可以执行完一条指令。此处采用三级流水线结构,(在我理解来,并不是所有的RISC-V架构的处理器都是三级流水线,应该是根据具体实现方式有关)。
一条指令,在处理器中主要完成以下步骤:
Ⅰ pc_reg模块:
时序逻辑电路,根据时钟产生指令地址,送入取指模块;
Ⅱ if模块:
组合逻辑电路,根据指令地址,访问外设ROM,ROM中存放相应的指令,并将指令送入到取指模块;
Ⅲ if_id模块:
时序逻辑电路,主要功能就是用来打拍,打一拍输出到id译码模块,提高系统频率,防止时序违例;
Ⅳ id译码模块:
组合逻辑电路,将命令进行译码,根据译码访问命令中的寄存器组,并将寄存器组的数据送入到下一个模块。
Ⅴ id_ex模块:
时序逻辑电路,主要目的就是打一拍输出,防止时钟频率较高情况下的时序违例。
Ⅵ ex模块:
组合逻辑电路,根据译码结果进行执行相应的操作,比如加法、减法等等。并将得到的结果回写到寄存器组中的目的寄存器进行存储。
【注】本来还应该有访存操作,只不过此处暂时没涉及到,暂不列出。
对于ROM外设,一般情况下,ROM内每个内存空间大小为8bit,主要用来存放各种指令,四个内存才可以存放一个完整的指令。不过后续实现的时候直接使用了32位的ROM简化设计。
综上所述,一条指令的执行过程有:取指、译码、执行、访存、回写。此处分三级流水线执行(也有五级流水线,典型的有MIPS架构处理器,关于MIPS架构处理器编写,可参考《自己动手写CPU》,获取方法同样在文末给出)。
取指阶段:从指令寄存器读出指令,同时确定下一条指令地址。
译码阶段:对指令进行译码,从通用寄存器中读出要使用的寄存器的值,如果指令中含有立即数,那么还需要将立即数进行符号位扩展,如果是转移指令,并且满足转移条件,那么给出转移目标,作为新的指令地址。
执行阶段:按照译码给出的操作数、运算类型,进行运算,给出运算结果。
访存阶段:如果是Load/Store指令,那么在此阶段会访存数据寄存器,反之,只是将执行阶段的结果向下传递到回写阶段,同时,在此阶段还要判断是否有异常需要处理,如果有,那么会清除流水线,然后转移到异常处理例程入口地址处继续执行。
回写阶段:将运算结果保存到目标寄存器。
流水线到底怎么个流水法?
执行第一条指令需要三个周期,执行第二条指令也需要三个周期,但是两条指令加起来只需要四个周期,因为执行完第一个指令的前一个步骤后,下一条指令可以立马接上,再次执行该步骤。
当然也可以按照每次只能单独执行一条指令设计,这样就不是流水线了,使用流水线可以增加运行效率,使系统速度提升;
4.一个需要注意的点
RISC-V的寄存器数组中,x0寄存器的值恒为32’d0;且不可修改。因为可以使用ADDI和ADD指令配合寄存器x0来实现NOP指令和MOV指令。
NOP指令:当前无操作,软件延时或者冲刷流水线;
MOV指令:通过加0的方式实现MOV指令。
5.再来一个需要注意的点
指令相关性冲突,如图所示
第一条指令,回写的目的寄存器为x7,但是第二条指令将其作为其中一个源寄存器,如果等待第一条指令的走完第三个周期去回写x7,那么第二条指令的第二个周期取到的x7的数值就是没有变化之前的数值,这显然不是我们想要的;
使用时序逻辑回写入寄存器组中比当前访问源寄存器的时刻慢了一个周期,所以在寄存器数组中,若收到的回写地址和当前正在读取的地址是同一个地址,则需要使用组合逻辑直接将该需要回写的数值赋给当前正在读出的数值。同时再将该数值使用时序逻辑写入寄存器组中。
(关于这一点,后续会结合程序进行说明)
6.环境搭建
目前需要的环境比较简单了,主要有:ModelSim用于仿真,notepad++用于程序编写;还有Quartus II软件,都是使用学习FPGA使用到的最基本的软件,这里就不放安装包了。
总结
接下来涉及到具体编码实现与测试,主要是实现以下几个模块:
八个模块,时序逻辑模块主要是进行打拍,组合逻辑模块进行相应的操作和运算。具体实现与测试过程,下期揭晓,敬请期待。
关注《FPGA学习者》后台回复【RISC】即可获取《手把手教你设计CPU——RISC-V处理器篇》pdf和RISC-V指令中文手册pdf。后台回复【MIPS】《自己动手写CPU》pdf。
最后
以上就是甜蜜芝麻为你收集整理的和你一起从零开始写RISC-V处理器(1)前言一、RISC-V简介二、指令实现的前期准备总结的全部内容,希望文章能够帮你解决和你一起从零开始写RISC-V处理器(1)前言一、RISC-V简介二、指令实现的前期准备总结所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复