trustintruth · 2020年05月25日

FPGA初始——自制CPU(上)

今天我开始填坑,带大家走进初始部分的最后一个部分:CPU。
作者:Trustintruth
来源:https://zhuanlan.zhihu.com/p/97019599

网上有许多教程写CPU的,但是我也是纠结了许久要不要做这一期CPU。最后还是决定做CPU,毕竟CPU是一个又装逼又不像图像处理要过多的数学公式推导的、工程量不小的工程。

好了下面我们不在说废话了,开始CPU!!(还是说句废话,CPU在我的理解中还是很考验逻辑的......哪里写的不太明白私信我,我一定修改!)

首先,CPU是啥?

CPU是计算机中进行各种运算和数据处理的装置。在内存中存储着由CPU可以执行的指令集所构成的程序,CPU首先读取(Fetch)内存中的指令,,然后对其要处理的操作进行译码(Decode),最后进行执行。

接下来我们首先来看这三步的具体操作:

取指:CPU会把将将要执行的指令从内存中读取出来。而完成这个任务的就是程序计数器(PC,Program Counter),他存着即将执行的指令的地址。指令的读取就是从PC的值输出至内存,在由内存返回地址中的指令(根据地址读取指令)。

解码:读取出来的指令根据指令集翻译成CPU各个模块能够理解的信号,指令中包括很多种,包括进行哪种运算、控制下一条的指令等,可以用来存数地址或者运算结果的寄存器称为通用寄存器(General Purpose Register)

执行:解码出来的信号控制着CPU要进行的操作,进行对应处理。

CPU的主要模块包括程序计数器,指令寄存器,指令解码器,寄存器堆,运算器

指令存储器和数据存储器分别用来存储所有的指令和数据。指令解码器用来解码当前要执行的指令,PC则用来存放当前要执行的指令的地址,通用寄存器堆里存放了若干个寄存器,运算器。由于操作有可能是进行运算,也有可能是从内存中读数取数,所以最后选择是存储计算出得数还是内存读出的数。根据上面我们说的操作,大体上我们可以画出这样的一附草图。
522.jpg
在上面讲述的时候估计很多小伙伴要问了:我们如何解码?解码当然就是按照指令的格式来将指令拆分,就像中国古语“庖丁解牛”所讲的。要想做“疱族后人”,后先来介绍指令集:

计算机指令就是指挥机器工作的指示和命令,程序就是一系列按一定顺序排列的指令,执行程序的过程就是计算机的工作过程。指令集,就是CPU中用来计算和控制计算机系统的一套指令的集合,而每一种新型的CPU在设计时就规定了一系列与其他硬件电路相配合的指令系统。而指令集的先进与否,也关系到CPU的性能发挥,它也是CPU性能体现的一个重要标志。每款CPU在设计时就规定了一系列与其硬件电路相配合的指令系统。指令的强弱也是CPU的重要指标,指令集是提高微处理器效率的最有效的工具之一。从现阶段的主流体系结构讲,指令集可分为复杂指令集(CISC)和精简指令集(RISC)两部分

522.jpg

相比而言,RISC的指令格式统一,种类比较少,寻址方式也比复杂指令集少。使用RISC指令集的体系结构主要有ARM、MIPS

而我们使用的为RISC 架构MIPS指令集,MIPS有三种指令格式:

不同格式的指令具有不同的功能,其中:

  • R格式指令为纯寄存器指令,所有的操作数(除移位外)均保存在寄存器中。Op字段均为0,使用funct字段区分指令
  • I格式指令为带立即数的指令,最多使用两个寄存器,同时包括了load/store指令。使用Op字段区分指令
  • J格式指令为长跳转指令,仅有一个立即数操作数。使用Op字段区分指令

也有的是这样解释的:


CPU自制入门配图

根据这样的指令分类,我们可以设计我们自己指令了,但是一定要按照指令集的格式要求,而且CPU内部的模块也要配合指令集来进行设计,所以在做自己的CPU第一步就是要设计好指令集。(此处为根据CPU自制入门设计时使用的指令集,未按指令种类分类,最后附一份另一版MIPS较全的指令集)
522.jpg
逻辑运算指令就是对寄存器中的数,或者是立即数(指令中包括的数)进行运算,再将结果存入寄存器中。含有立即数的指令需要将16位的立即数扩充到32位,通常分为高16位全扩充及符号位扩充两种。

算数运算指令也是将寄存器中的数或者立即数进行算术运算,存储至寄存器中。在运算中(加法和减法)分为有符号和无符号两种,,他们的区别在于是否检测溢出(由于存在符号位,所以溢出标志不同)
522.jpg

移位指令即为移位

分支指令是一个非常重要的指令,他会改变程序流程。首先分支指令会进行判断,若判断成立(分支成立),那么下一条指令就会发生改变。目标地址由PC与符号扩充后的立即数相加得到。而JMP指令用来强制跳转到寄存器指定的地址,CALL指令用来调用寄存器指定地址出的子程序。他们两个都是无条件跳转语句,但是CALL指令会存储两条之后的指令地址,即存放“CALL指令地址+8”,他的下一条指令会被当做延迟间隙执行。如


522.jpg

内存访问指令用来从内存中读取或写入数据

写入地址由寄存器与符号扩充的立即数相加得到。,执行内存访问指令时要对地址进行对其检测。

这里我们提出一个概念,叫做数据通路,数字系统中,各个子系统通过数据总线连接形成的数据传送路径称为数据通路。

草图中已经大致讲述了我们的主要部件,而数据的流向我们也摸了差不多,**最重要是,根据指令集你的指令输入后,如何拆解指令CPU已经知道了。但是拆解之后各部分分别代表着不同的意义(比如寄存器地址、立即数、进行操作的类型),将这些信息(信号)交给对应的模块(部分),寄存器地址交给寄存器读取里面的数据,立即数送给扩展部分等等,这才是整个系统设计的第一个难点,数据是如何在你的CPU中流动的。**下一个目标就是如何得到一幅数据通路:

下一节我们详细的将这张图的由来,并设计其中的各个模块。

本来想控制篇幅,但是东西太多了。下次争取更加精简!

附:

http://www.cirmall.com/bbs/thread-161594-1-1.html
可以从这里下载数据通路和指令集,也欢迎大家多多在这个论坛发表见解啊

推荐阅读

关注此系列,请关注专栏FPGA的逻辑
推荐阅读
关注数
10606
内容数
562
FPGA Logic 二三事
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息