计算机组成原理alu功能实现代码_SAST Weekly | 在?来造计算机!

SAST weekly是由电子工程系学生科协推出的科技系列推送,内容涵盖信息领域技术科普、研究前沿热点介绍、科技新闻跟进探索等多个方面,帮助同学们增长姿势,开拓眼界,每周更新,欢迎关注,欢迎愿意分享知识的同学投稿eesast@mail.tsinghua.edu.cn

61885040559fe599b5d1005d4ad773bc.gif 78816367a0939cb3540cfae63f616f8b.gif 61885040559fe599b5d1005d4ad773bc.gif 779f3fa8f94dc4e2dfd21ba40a1348e2.gif

什么是 计算机组成 

一般提到计算机底层的实现,我们会回想起清华信院学生被《电子电路与系统基础》《计算机组成原理》《计算机体系结构》所支配的岁月。

可以看到,计算机的“底层”其实也可以再细分成许多不同层级。从下而上,有基础电子电路、逻辑门、组合与时序逻辑、有限状态机、CPU与Memory;从上而下,有高级语言、虚拟机、汇编语言、机器语言、指令集架构(ISA);而CPU和ISA之间还有一些微架构、互联策略、资源分配等等内容,才能从上至下连成一个完整的计算机。

从学术的角度上来讲,计算机的硬件部分主要分为三大层:Hardware是地地道道的硬件层、Organization(也叫Microarchitecture)是基于一定抽象的模块化电路设计、ISA(Instruction Set Architecture)则提供了软硬件的接口。

作为一名不学无术的微纳电子系学生,在软件上整活是不可能了,基础的逻辑电路又没啥意思,所以我把魔爪伸向了中间CPU设计和体系结构的部分。

779f3fa8f94dc4e2dfd21ba40a1348e2.gif

为什么要聊 计算机组成 

很本质的理由:下学期要学体系结构,搞点组成的事情可以作为背景知识;假期看了Nand2Tetris,感觉自己萌萌哒。

很历史的原因:我一直想搞清楚从基础电子电路到一台可以跑的计算机中间到底经历了什么。

在做这个小项目的过程中,我一方面了解了计算机的组成部分和一些思想,另一方面熟悉了FPGA的开发流程,所以想跟大家简单分享一下。

61885040559fe599b5d1005d4ad773bc.gif

本篇推送前五章介绍如何用用Verilog写出一台极其简单的微型计算机,并实际跑在FPGA上。第一章先给出一个非常简易的ISA;根据ISA设计出CPU内的电路;根据冯诺依曼架构建立CPU和Memory的互联,并通过Verilog实现;最后添加I/O设备,并解决一个重要的时序问题。

整篇推送默认读者有一些数字电路和Verilog语言的基础,不会在基础的部分过多停留。

Credit to Nand2Tetris,强推好课。推送第一部分的指令集和电路设计大多来源于它,一些逻辑解释和FPGA的实现代码是手写的。

61885040559fe599b5d1005d4ad773bc.gif

冯诺依曼架构

3d743f9014734fbdcc973a1b0e44527b.gif 9c65820a35f303e3a59e30b0afa57f9f.png

在讨论具体设计之前,我们先鸟瞰一下计算机的整个硬件部分应当是什么样子的。

从上层看,计算机主要的功能是由指令控制的运算和存储,所以有运算、存储、指令三个大单元,它们分别是CPU、数据内存、指令内存。这样的结构也叫做哈佛架构,而冯诺依曼架构中两个内存是一体的,不过我们暂不区分。

这样的架构在逻辑上可以如下图表示。

6d0f1f15026fd3b91dd9f75c2bffdad3.png

而具体到模块化电路的实现,则可以参照下图的互联方式。

52882ae4f3ebc3573f0b43252177ea63.png

两个Memory在这个简单的小实验中实际上是简单的寄存器堆,但是在现代计算机中,一般是多层级的存储系统。

CPU是核心的译码和计算单元,其中译码在硬件上主要通过MUX和各个寄存器的控制端实现,而计算单元则以ALU(算术逻辑单元)为核心。简单来说,ALU是一个高级加法器——它被指令控制,可以进行变量加减、常数加减、按位逻辑等等,从而达成多样的计算。ALU的设计需要考虑到指令集如何、需要达成什么样的计算目标,所以我们需要先给出高层的指令集架构设计。

指令集架构

3d743f9014734fbdcc973a1b0e44527b.gif 9b474f1d8a37b939c358299bcbefac30.png

在讨论指令集之前,先给出一些约束:指令宽度16b,内存32K字,地址宽度15b。在CPU中有两个寄存器,分别称为AReg(地址寄存器)和DReg(数据寄存器);数据内存中当前被选中的内存块称为MReg。其中,AReg的输出端会直接连接至数据内存的地址选择端;同时会连接到程序计数器,从而在特定跳转条件下,会对指令内存的选址产生影响。

da8f3e9189b26bb9a9f28e4ef2434f12.png

在给出上述约束后,讨论CPU所能执行的基础运算(也就是ALU的功能)。通过宽度为6b的指令,第一位表示是否将x置零,第二位表示是否将x按位取反;三四位同前两位,只不过作用与y;第五位决定进行加法操作还是按位与操作;最后一位控制计算结果是否取反后再输出。

通过这六位的控制,我们可以做出两个变量的加减、变量自身加减一、变量的按位逻辑操作等等。具体指令与功能的对照可见下图。

81ad21e92f37981d4d9bf861e22534df.png

最后来说我们的指令集,它包含两条指令。

指令一的格式为0aaaaaaaaaaaaaaa,它的功能是将15位的a直接存储到AReg中。进而根据连接约束,MReg也会变为地址所对应的内存块。

指令二的格式位1xxaaabccccccddd,功能是使用A/M/DReg内的数据进行计算,并根据计算结果与零的大小关系判断是否进行跳转。具体来说,三位a分别控制计算结果是否要写入A/M/DReg,b控制ALU的两位输入是AD还是MD,六位c直接作为ALU的控制指令,三位d分别控制小于、等于、大于时是否进行跳转。

通过这两个指令,我们可以实现所有基础操作,进而成为一个完备的系统。

7f5b95458738341859cbb7d03b75cbcd.png

CPU设计

3d743f9014734fbdcc973a1b0e44527b.gif 9c65820a35f303e3a59e30b0afa57f9f.png

根据所给的指令集,我们已经知道CPU需要处理什么样的指令、需要完成什么功能。根据这些设定,可以很自然的做出CPU的设计。

首先,根据AReg的约束,其输出直接作为数据内存的选址,以及程序计数器的输入。

d04c667dae275969cae346a028970715.png

然后,ALU的输入为DA/DM,通过指令控制,所以中间插入一个MUX。

683e4b4bdca619ddba7e03f52c6aac90.png

第三,ALU的输出会作为A/M/DReg的输入。

426c5526326a1c77298d17f66fd84717.png

第四,AReg的输入还可以是指令一的内容。

786b69769f6361d28a6cf1adf74b0825.png

最后,将指令分布到MUX和Reg的控制端。

12f6074d12f564d77d947a60922b879d.png

这样,(在不考虑时序问题的情况下)我们就做出来一个满足前提约束,并可以按照指令集工作的CPU了。

FPGA实现

3d743f9014734fbdcc973a1b0e44527b.gif 9b474f1d8a37b939c358299bcbefac30.png

先进行CPU的设计。按照前面叙述的CPU连接关系,需要先设计出一个ALU模块和一个PC模块(一个简单的累加寄存器)。

df83eb6f6fe34ecb43ee2f6448f220fb.png 388dbbd5e2b229ec862c18f4a7822902.png

再将各个组成部分相连,就得到了CPU。

44f82fd3ef8805ec9781c175e8ec4790.png

而Memory的部分则需要用CoreGenerator工具的辅助加入两个Block RAM的IP核,按照需要进行配置后直接调用模块即可。

4c8c6d5f2fd1908784e3e50289eb73c8.png

最后,将三大部分按照冯诺依曼架构连接。

1fab7c4267721258cbce44a06c31fec5.png

这样,一个看起来可以工作的微处理器就造好了。接下来的问题是加入I/O设备,以及对其中的一些问题进行修正。

加入I/O设备

3d743f9014734fbdcc973a1b0e44527b.gif 9c65820a35f303e3a59e30b0afa57f9f.png

对于这里的I/O设备(按钮和八段数码管),我们选择一种简单的DMA的控制方式。我们分别给输入和输出配置一个硬件的驱动接口,并且将相应的内存访问权限完全下放给I/O设备,即输入设备直接控制RAM,输出设备由RAM中的某块内存内的值直接控制。具体代码如下。

59deebb489ceff321b6da7fb11335903.png 9bac4841fa49b8854364a9502d362f1c.png

解决时序问题

3d743f9014734fbdcc973a1b0e44527b.gif 9b474f1d8a37b939c358299bcbefac30.png

所有以上的设计都仅在逻辑上成立,但没有仔细考虑时序的问题。如果RAM的访问时间远小于一个时钟周期,则上述结构运行顺利,可以视为一个“取指-运算”的二级流水线。但是如果RAM需要一个时钟周期进行访问,那么AReg改变后,取到正确MReg的值需要多一个周期,这样就会出现竞争问题。所以我们在遇到AReg值改变时,需要令整个系统halt一个周期,保证RAM的输出正确。这样就成为了一个“取指-运算-访存”的三级流水线。

69e5cc7482fafe1d323d986648121461.png

那么以上,就是我在假期里学了前半部分Nand2Tetris后,用FPGA做的一个微型计算机项目。在这个过程中,我从最底层的电子电路逐渐向上,认识到一个最简单计算机硬件的全流程。在此后,讨论到现代计算机体系结构时,其中很多概念都可以在这个微型计算机中找到雏形,从而更好地理解计算机体系结构的内容。

c3f159db6cae257eec9ce8506dfa41fe.png e8c5dcc9a86ef3e53bfa2d11540ec369.png

参考文献

  1. Nand2Tetris: https://www.nand2tetris.org/

04c1e48305d6183b5b72066c3c6aa1cb.gif

撰稿人:张亦弛

审稿人:钟宏涛

1dcd51a2b0d54ddc14cabf887100773c.png
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值