网站项目建设流程图,阿里云搭建网站多少钱,网站开发技术有哪些,wordpress文章底部插件博主简介#xff1a;努力学习的22级计算机科学与技术本科生一枚#x1f338;博主主页#xff1a; Yaoyao2024往期回顾#xff1a; 【计算机系统架构】从0开始构建一台现代计算机|布尔代数和基础逻辑门|第一章每日一言#x1f33c;: 今天不想跑#xff0c;所以才去跑… 博主简介努力学习的22级计算机科学与技术本科生一枚博主主页 Yaoyao2024往期回顾 【计算机系统架构】从0开始构建一台现代计算机|布尔代数和基础逻辑门|第一章每日一言: 今天不想跑所以才去跑这才是长距离者的思维。 ——村上春树 0、前言
一言以蔽之利用上一模块中构建的芯片组我们现在将着手构建一个加法器系列–专为数字加法而设计的芯片。然后我们将向前迈出一大步构建一个算术逻辑单元。算术逻辑单元设计用于执行一整套算术和逻辑运算是计算机的计算大脑。在本课程的后半部我们将使用 ALU 作为核心芯片并在此基础上构建计算机的中央处理器CPU。由于所有这些芯片都以二进制数0 和 1为运算单位因此我们将从二进制运算的总体概述开始本模块的学习然后再深入学习 ALU 的构建。关键概念二进制数、二进制加法、二进制补法、半加法器、全加法器、n 位加法器、计数器、算术逻辑单元 (ALU)、组合逻辑。
1、二进制数
其实在上一章节我们并没有讲到“数”的概念以及“进制”的概念我们只是有两个相反概念的布尔值1和0对他进行相应各种布尔逻辑运算And,Or,Not)。
只通过上述这样一位一位的布尔逻辑运算肯定和我们复杂的计算机还差的远。既然是计算机”计算“必然要有数。如何通过仅有的0,1两个符号表示数呢
我们可以将其进行组合
通过将0,1进行组合像99,20这样将0,1,2,3,4,5,6,7,8,9进行组合一样表示不同的数。有多少种组合即可表示多少个数。
于是我们通过这种0,1进行组合来表示数其实我们用到的十进制就是用10个符号进行组合来表示数的
1.1、进制的概念
首先我们要清楚对于我们的计数系统每一个数字所在的位置合这个数字代表的意义有关
为什么这么说呢假设我们穿越到原始时代使用木棍进行计数一个木棍代表一个猎物那么假如有11个猎物你会怎么计数 11111111111 1 1 1 1 1 1 1 1 1 1 1 11111111111
OK我们会用11个木棍排在一起代表有几个猎物。
再看我们现在的技术系统表示11个猎物是11咿呀怎么只有”两个木棍,这是因为这两个1的位置不同代表的意思不同: 11 1 × 1 0 1 1 × 1 0 0 11 1×10^1 1×10^0 111×1011×100
前一个1表示10后一个1表示1。
而这种每个数字所在位置代表的实际个数就是进制。
只使用单个0~9进行表示最多能10个数也就是“逢10进1要想再多表示怎么办给不同位置的数赋予不同的意义。
同样的只使用0,1最多只能表示2个数0和1要是想表示2怎么办10也就是“逢2进1这个时候1表示的是满了的20表示单个的并没有。
这就是进制因此只使用0,1且带有位置权值的计数系统则为二进制计数系统。
1.2、二进制转为十进制
我们都知道每一位的0,1代表什么意思把这个位置的数✖对应该位置的权值即可化简出对应的10进制数。 1.3二进制转10进制
1.4固定位宽(Fixed word size)
如1.2k的取值代表的计数01序列长度也称为位宽位宽不同0,1序列所表示的数字最大限度就不同。
在计算机底层一个整数的位宽当然不是无限的而是固定的通常是8bits) 但是我们忽略了一点负数Negative Number)
但是也有方法解决这个时候我们将0,1序列的最左边一个比特位设为符号位看这个位置的符号代表的含义变了哦若位1则代表是负数否则则是正数。 Tips: 不过在计算机内部负数到底是如何表示的呢? 仅仅是牺牲一个比特位作为符号位就够了吗当然不是关于负数在计算机内部的表示和存储会在第3节详细讲解。 2、二进制加法
上节我们讨论了如何使用0,1来构建我们的二进制计数系统那么有了数字这节我们来看看如何使用二进制数字进行基本的算术运算吧~
AdditionSubstractionWhich is greater?MultiplicationDivision 首先我们知道基本的算数运算就是以上6种但是设计了加法的硬件部分实现了两个数相加的底层逻辑其他的也可以实现。为什么 一言蔽之实现了加法,其他运算也可以转换为加法运算
对于减法、比较大小两个运算实现了加法就可以实现减法: 减法可以转换为负数相加那对于乘法、除法呢这些不会去专门设计一个硬件电路去实现当然在不考虑成本和效率的情况下当然可以设计一个专门的芯片因为它本身其实就是 循环加、循环减法可以在计算机系统的 软件层次去编写库函数去实现实际上后续也会讲到是在操作系统的数学库函数里实现的。
总而言之所有 运算的根基就是加法实现了加法其他运算也就水到渠成。
那么我们下面就来看看计算机底层是如何实现加法运算的。
2.1我们是如何做加法的
让我们回到小学一二年级看看我们对十进制的加法是如何进行的 那么对于二进制计算其实也是一样的从右往左一位一位的计算把当前两位相加得到当前位的结果和进位、下一位的结果和进位是由下两位以及进位相加得到。 2.2溢出Overflow
但是这样做有一个问题最高位溢出Overflow
因为根据上文我们知道整数存储在计算机底层具有固定的位宽(Fixed Word Size)因此如下图所示当相加的两个二进制整数太大导致结果表示超过了位宽即叫做溢出
那么这种情况下计算机会怎么处理呢抛出异常报错 实际上计算机处理方法是To Do Nothing. 没错当两个整数相加结果超过位宽计算机只会截取并且保存从右到左固定位宽大小的数据而直接将其溢出的部分舍去。 Tips虽然这样看起来很不合理因为对于程序员来说你必须清楚你的计算是否会溢出以避免最终得到的结果不正确。但是我个人认为这种处理方法实际上为后面要讲到的负数运算提供了便利。 ♀️下面我们来看看如何设计实现加法的硬件芯片吧这将分为三个阶段这是一个逐渐抽象的过程从半加器到全加器再到真正的多位加法器后者以前者为基础进行实现。
2.3半加器HAHalf Adderadds two bits)
半加器是考虑整输入只有两个待相加的比特位输出结果为当前位计算结果(sum) 进位(carry) 对于只有2个bit位相加的逻辑我们可以使用真值表进行表示随后确定半加器的芯片设计
但是这种半加器的限制是它没有考虑当前计算位的进位是多少而默认为0)而我们知道实际计算过程中除了要考虑当前位的两个数还需要考虑上一位计算结果得到的进位然后一起将这3个比特位的值相加得到最终结果以及进位。因此我们需要能够相加3比特位的芯片全加器。
2.4: 全加器FAFull Adderadds three bits) 事实上全加器可以由2个半加器组合得到这也是半加器名字的由来 2.5加法器AdderAdds two numbers
多位加法如下图其实就是从右往左做单位全加比如黄色方框两个数相加得到该位的结果以及进位进位参与下一位的绿色方框的运算…依次进行。
实现起来也很简单我们可以使用1个半加器15个全加器串接或者直接使用16个全加器串接即可 3、负数
在前面其实讲二进制数的时候其实提到过负数的表示牺牲最高位的数据位设为符号位以区别负数。
但是计算机底层内部的负数表示与存储真的是这样吗其实不是这么简单因为如果简单的这样处理会引发一些问题
0000和1000表示0和-0有两个0的存在这样很不优雅elegant)且会带来一些麻烦减法和加法无法使用同一个硬件电路需要明确得设计出两个不同的电路进行处理因为即使用整数加上负数表示简繁得出来的结果并不正确很麻烦
所以事实上计算机底层的负数表示并不是上述那样而是使用了二进制补码2’s Complement的方法来表示负数这种方法不仅使得正数和负数的表示十分方便和优雅且在计算方面减法和加法使用同一个加法电路即可完成极大的降低了成本。 最棒的一点就是当我们使用上述“补码”的方式去表示负数时当我们进行减法时减法其实就是负数的加法我们只需要使用一个加法芯片即可完成。 如上图当我们计算-2-3时因为14 2^4 - 2代表的就是-2那么实际上这个表达式就是两个负数相加那么我们将负数对应的二进制补码相加得到的结果也就是这个计算结果也是一个二进制补码它表示的负数就是正确结果。你看这里其实最高位被舍弃了我们在讲正整数相加时如果溢出位被舍弃得到的结果是不正确的但是在减法这里其实正是因为这个舍弃得到的结果才是正确的这也是为什么我在上文讲溢出的时候说我认为溢出不报错的原因就是因为它其实在减法运算过程中起到了一定的作用。
嗯上述讲解是不是感觉很神奇用补码这种形式表示负数进行负数的加法得到的结果也是正确结果的表达形式。那么下面来讲解一下这是怎么发生的
首先我们要明确一点的是使用补码表示负数即 − x 2 n − x -x 2^n - x −x2n−x
也就是说我们看到 2 n − x 2^n-x 2n−x, 那么它就是 − x -x −x这点必须明确。
下面从2种情况来论证当使用补码来表示负数时那么减x就是加上-x: 下面假设a0b0 1) a-b a − b a ( − b ) a ( 2 n − b ) 2 n − ( b − a ) a - b a (-b) a (2^n-b) 2^n - (b-a) a−ba(−b)a(2n−b)2n−(b−a) { if ba则 ( a − b ) 0 , 结果为 − ( b − a ) 就是 2 n − ( b − a ) if ba则 ( a − b ) 0 , 结果为 a − b 就是 − ( b − a ) \begin{cases} \text{ if ba} 则(a-b)0,结果为-(b-a)就是2^n - (b-a)\\ \text{ if ba} 则(a-b)0,结果为a-b 就是-(b-a) \end{cases} { if ba则(a−b)0,结果为−(b−a)就是2n−(b−a) if ba则(a−b)0,结果为a−b就是−(b−a)
2) -a-b − a − b ( − a ) ( − b ) ( 2 n − a ) ( 2 n − b ) 2 n − ( b a ) − ( a b ) -a - b (-a) (-b) (2^n-a) (2^n-b) 2^n - (ba) -(ab) −a−b(−a)(−b)(2n−a)(2n−b)2n−(ba)−(ab)
这里注意有一个关键就是 ( 2 n − a ) ( 2 n − b ) 2 n − ( b a ) (2^n-a) (2^n-b) 2^n - (ba) (2n−a)(2n−b)2n−(ba) 这里为什么有一个2^n直接被丢掉了你想的没错这里就是两个负数最高位符号位都是1, 相加溢出直接丢了2^n。 所以综上论述使用补码来表示二进制负数是完全可以的。
但是现在还差一点比如输入a和b(a0,b0),求a-b为了能够实现上述的把减法转换为加上负数我们还需要把b转为-b即输入x求-x的求补码电路设计 如上图我们的目标是求2^n-x但这本身就是一个减法直接求当然是行不通的但是我们可以转换一下。
首先看到上述等式的后半部分 (2^n-1) - x它本质是将正数x取反我们前面一章已经学会了如何进行多线路的取反操作再看到等式前面的1这就更简单啦因为我们前面已经设计出来了加法电路。
综上我们使用了已有的取反加法电路实现了求补码的操作求补码操作是后续负数加法的基础只有先得到这个负数的二进制补码表示才可以对其进行加法操作。
下面这个例子讲了如何求-4的补码: 很简单
首先将其正数4的二进制位全部进行翻转得到的结果1 Tips: 其实到这里老师并没有讲到什么原码、反码、补码的概念其实说实话也没有必要了解了到这里的话但是我发现国内讲负数这块和这门课老师讲的完全不同这门课则是从为什么需要这么表示开始讲到补码是专门位计算机表示负数的一种表示方法非常有逻辑。而国内则是一开始上来就讲原、反、补什么正数的原反补相同什么什么的搞初学者晕头转向最后记下来了吧其实也不知道为什么要这样做。我前面在学习原反补的时候也专门写了一篇博客【C语言篇】移位操作符、位操作符详解–图解演示、例题讲解、经验总结 看完这节课我才明白原码、反码其实根本没有必要存在计算机里面负数就一个补码而正数也不存在什么原反补。原反补只能说是在计算负数的补码时候的一种方法吧这里也只是基于现在我的认知的一个了解如果有错误请在评论区告诉我 4、ALU算术逻辑单元
4.1 介绍
ALUAlgorithm Logic Unit是冯诺依曼计算机体系结构种的重要组成部分
让我们聚焦到ALU它具有两个多位输入input1,2、计算函数f计算结果输出。其中计算函数f是一系列预先确定好的函数算术运算、逻辑运算)种的一个这些函数共同定义了ALU的功能。
⭐ALU该包含哪些函数 ♀️事实上ALU并不需要包含所有的运算函数因为计算机系统分为硬件Hardware和软件Software两部分比如当我们硬件中实现了加法那么乘法、除法可以使用软件编写程序乘法循环➕除法循环➖完成这取决于你的取舍设计特定的硬件肯定成本更高但是运算起来速度快。
本课程将设计一个简单的ALU如下图。
它有2个16位的输入位x、y有1个16位的计算结果输出位out有6个控制位负责控制计算函数的选择这个AL一共包含了16个运算函数且有2个1bit位的输出zr、ng 稍后讨论
关于控制位给控制位输入特定的值则会进行特定的运算
4.2工作原理
⭐1) 控制位介绍
在这门课的ALU具有6个控制位它们表示对输入信号的处理输入相同控制位不同产生的逻辑运算的结果就不同输入不同控制位相同运算逻辑即运算函数不变。 下面这是整个ALU的逻辑运算表 下面以!x这个运算举例说明这确实是可行的 Tips不知道在真正学习ALU的控制位进行控制从而进行不同函数运算之前大家会不会像我一样认为这个控制位就是类似于选择器的那个选择信号数据一股脑输入之后会进行所有运算然后选择一个运算函数的运算结果进行输出 但是实际的控制位并不是这种单纯的选择作用。它把一个大的选择分成很多细小的选择对X取非、And还是Add…分成这种细小操作然后用控制位对这些细小操作是否执行进行控制我觉得是组合从而组合而成一个特定的运算函数。我觉得这样做有很大一个好处就是基本芯片的复用或者说还是计算机里的抽象思维因为如果把Add和And这些芯片一个个单独写出来其实它们有很多重复的基本操作取非呀、置为0呀…)于是把这些基础的操作单独提出来然后使用控制位对其进行控制选择对这些基础操作进行组合从而得到特定的操作函数。我相信如果是我上面图那样每一个特定函数都写一个特定的芯片这样的制造成本肯定比将基本的芯片进行提取然后用控制位进行控制和选择高得多。 4.3总结 5、项目Project02
5.1半加器HalfAdder 半加器很简单了两个输入两个输出分开来看Sum的运算逻辑就是异或XorCarry的运算逻辑则是And把这两个结合即为半加器 /*** Computes the sum of two bits.*/
CHIP HalfAdder {IN a, b; // 1-bit inputsOUT sum, // Right bit of a b carry; // Left bit of a bPARTS: Replace this comment with your code.Xor(a a, b b, out sum);And(a a, b b, out carry);
}5.2全加器FullAdder
全加器也很简单它可以由两个半加器组合而来
/*** Computes the sum of three bits.*/
CHIP FullAdder {IN a, b, c; // 1-bit inputsOUT sum, // Right bit of a b ccarry; // Left bit of a b cPARTS: Replace this comment with your code.HalfAdder(a a, b b, sum s1, carry c1);HalfAdder(a s1, b c, sum sum, carry c2);Or(a c1, b c2, out carry);
}5.316位加法器Add16
多位加法器也很简单把16个全加器进行串接即可
/*** 16-bit adder: Adds two 16-bit twos complement values.* The most significant carry bit is ignored.*/
CHIP Add16 {IN a[16], b[16];OUT out[16];PARTS: Replace this comment with your code.FullAdder(a a[0], b b[0], c false, sum out[0], carry c1);FullAdder(a a[1], b b[1], c c1, sum out[1], carry c2);FullAdder(a a[2], b b[2], c c2, sum out[2], carry c3);FullAdder(a a[3], b b[3], c c3, sum out[3], carry c4);FullAdder(a a[4], b b[4], c c4, sum out[4], carry c5);FullAdder(a a[5], b b[5], c c5, sum out[5], carry c6);FullAdder(a a[6], b b[6], c c6, sum out[6], carry c7);FullAdder(a a[7], b b[7], c c7, sum out[7], carry c8);FullAdder(a a[8], b b[8], c c8, sum out[8], carry c9);FullAdder(a a[9], b b[9], c c9, sum out[9], carry c10);FullAdder(a a[10], b b[10], c c10, sum out[10], carry c11);FullAdder(a a[11], b b[11], c c11, sum out[11], carry c12);FullAdder(a a[12], b b[12], c c12, sum out[12], carry c13);FullAdder(a a[13], b b[13], c c13, sum out[13], carry c14);FullAdder(a a[14], b b[14], c c14, sum out[14], carry c15);FullAdder(a a[15], b b[15], c c15, sum out[15], carry c16);
}5.4进位器Inc16
进器其实就是一个简易版的加法器它的输出结果是输入值1
/*** 16-bit incrementer:* out in 1*/
CHIP Inc16 {IN in[16];OUT out[16];PARTS: Replace this comment with your code.Add16(a in, b[0] true, b[1..15] false, out out);
}Tips: Inc16在本次构建ALU时并不会使用后续用到 5.5算术逻辑单元ALU // This file is part of www.nand2tetris.org
// and the book The Elements of Computing Systems
// by Nisan and Schocken, MIT Press.
// File name: projects/2/ALU.hdl
/*** ALU (Arithmetic Logic Unit):* Computes out one of the following functions:* 0, 1, -1,* x, y, !x, !y, -x, -y,* x 1, y 1, x - 1, y - 1,* x y, x - y, y - x,* x y, x | y* on the 16-bit inputs x, y,* according to the input bits zx, nx, zy, ny, f, no.* In addition, computes the two output bits:* if (out 0) zr 1, else zr 0* if (out 0) ng 1, else ng 0*/
// Implementation: Manipulates the x and y inputs
// and operates on the resulting values, as follows:
// if (zx 1) sets x 0 // 16-bit constant
// if (nx 1) sets x !x // bitwise not
// if (zy 1) sets y 0 // 16-bit constant
// if (ny 1) sets y !y // bitwise not
// if (f 1) sets out x y // integer 2s complement addition
// if (f 0) sets out x y // bitwise and
// if (no 1) sets out !out // bitwise notCHIP ALU {IN x[16], y[16], // 16-bit inputs zx, // zero the x input?nx, // negate the x input?zy, // zero the y input?ny, // negate the y input?f, // compute (out x y) or (out x y)?no; // negate the out output?OUT out[16], // 16-bit outputzr, // if (out 0) equals 1, else 0ng; // if (out 0) equals 1, else 0PARTS: Replace this comment with your code.//processX:Mux16(a x, b false, sel zx, out zeroX);Not16(in zeroX, out notX);Mux16(a zeroX, b notX, sel nx, out nX);//processYMux16(a y, b false, sel zy, out zeroY);Not16(in zeroY, out notY);Mux16(a zeroY, b notY, sel ny, out nY);//fAdd16(a nX, b nY, out addXY);And16(a nX, b nY, out andXY);Mux16(a andXY, b addXY, sel f, out fXY);//outPutNot16(in fXY, out nFXY);Mux16(a fXY, b nFXY, sel no, out out,out[15]ng, out[0..7]outa, out[8..15]outb);//zrOr8Way(in outa, out or1);Or8Way(in outb, out or2);Or(a or1, b or2, out temp);Not(in temp, out zr);
}