《小学生也看得懂的红石计算机教程:从零构建自己的红石计算机》

·

楼主注意到国内一直缺乏着面向红石玩家的数点计算机教程,
为了填补此漏洞,也为了水贴(划掉)
楼主决定从今天起,更新一个面向所有玩家,不需要任何基础,
就算是小学生也没有阅读障碍(当然不识字除外)的计算机教程.
目录会发在二楼,方便玩家浏览,
本帖于minecraft吧,红石电路吧等贴吧不定期同步更新不定期更新.
(封面来自ox的64位计算机的无许可联动)

楼主 savenseg  发布于 2019-03-16 11:01:00 +0800 CST  
这层是目录,格式是
Chapter[n]-n.i【标题】

楼主 savenseg  发布于 2019-03-16 11:02:00 +0800 CST  
不许抢楼

楼主 savenseg  发布于 2019-03-16 11:02:00 +0800 CST  
===============================================================


【###======
【#CHAPTER[0]-0.1【前言】
【###======


本教程的目的是让无基础玩家了解红石计算机的基本设计原理。
考虑到红石电路与读者的特殊性,
教程对计算机体系结构知识做出了必要的取舍,
另外:>>>不建议中小学生在红石上消耗过多时间而耽误学习<<<
诺对想对相关知识进行进一步的深入了解,
可以包括但不限于地参考如下几本书籍:(其实就是专业课大礼包)


《数字电子技术基础》高等教育出版社
《汇编语言》清华大学出版社
《计算机组成与设计:硬件、软件接口》机械工业出版社
《计算机体系结构量化研究方法》人民邮电出版社
《现代操作系统》机械工业出版社
《算法导论》机械工业出版社
《编译原理》机械工业出版社
《计算机网络系统方法》机械工业出版社
《计算机网络自顶向下方法》机械工业出版社
===============================================================

楼主 savenseg  发布于 2019-03-16 11:02:00 +0800 CST  
百度排版***,把我的控格全删了,打不了字符画

楼主 savenseg  发布于 2019-03-16 11:24:00 +0800 CST  
===============================================================
【###======
【#CHAPTER[0]-0.2【内存模型】
【###======
内存是用来存东西的存储器,
存储器由n个存储单元顺序排列构成,
每个存储单元有一个独立的编号,
存储器要提供的功能就是:
玩家可以给定一个编号,让存储器找到编号对应的那个单元。
然后玩家可以再选择操作对这个单元里的内容进行读取,覆写.
读取的意思就是把单元里的内容复制一份出来.
覆写的意思就是玩家提供了一个新的数字,写到了单元里
并且覆盖了原有的内容.
举个例子:
[0]0
[0]1
[0]2
[0]3
这里每个方框都是一个单元,方块后面的数字就是单元对应的编号,
而方框里的数字就是这个单元里的内容。
这里我们先定义两个操作:
READ n
WRITE n,(a)


READ n的意思是从编号为n的单元中读取那个数字,
这里我们另外让他读取出来后数字会直接被打到屏幕上。


WRITE n,(a)的意思是用a覆写第n个单元。
###################################################
%例子1:
>>>
[0]0
[0]1
[0]2
[0]3


>>>执行WRITE 0,(450)


>>>
[450]0
[0 ]1
[0 ]2
[0 ]3


>>>输出:无
#===============================================#
可以看到执行WRITE 0,(450)后,
编号为0的内存单元中的内容变成了450
因为WRITE这个操作不会造成一个输出,所以现在还没有输出
###################################################
%例子2:
>>>
[450]0
[0 ]1
[0 ]2
[0 ]3


>>>执行READ 0


>>>
[450]0
[0 ]1
[0 ]2
[0 ]3


>>>输出:450
#===============================================#
可以看到执行后编号为0的单元中的内容并没有改变,其他的也是如此,
但是我们得到了一个为450的输出,这个输出正是来自编号为0的单元!
###################################################


总的来说,存储器就是这样一个可以提供给操作者写入,读取数据
的一个存储体,就像***稿纸上用铅笔写字,
读取就是用眼睛从草稿纸上读出你写的内容,
覆写就是先用橡皮擦擦除原先的旧内容,然后再写下你要写的新内容。
在计算机的实际运行中,读取和覆写会交给CPU来执行
===============================================================

楼主 savenseg  发布于 2019-03-16 11:30:00 +0800 CST  
===============================================================
【###======
【#CHAPTER[0]-0.3【计算机结构的简化模型】
【###======


计算机的结构可以简单表示成:
------------------------------

))CPU-RAM-IO((
------------------------------
其中CPU与RAM相链接,RAM与IO相链接。


-.
CPU的全称是中央处理器(CentralProcessingUnit)
它是整个处理器的核心,负责执行程序,处理数据。


-.
RAM的全程是随机存取存储器(RandomAccessMemory)
它是程序与数据的载体,所有的程序和CPU的计算结果等都存储在其中。


-.
IO也就是输入/输出(Input/Output)
计算机的外部设备(比如显示器,键盘)都经由IO与CPU进行沟通。
===============================================================

楼主 savenseg  发布于 2019-03-16 11:36:00 +0800 CST  
===============================================================
【###======
【#CHAPTER[0]-0.4【计算机执行过程的简化模型】
【###======
那么计算机是怎么运行的呢?
我们可以分析一个简化的过程:
------------------------------------------------------------------------------------
按下开机按钮->执行第一个指令->执行更多指令->按下关机按钮
------------------------------------------------------------------------------------
但是在此之前先纠正一下我们的用语,
前面我们提到了在内存中每个内存单元都有一个独一无二的
单元编号,现在我们把这个编号叫做内存的地址,
也就是说我们今后将"编号n"改名为"地址n"
通俗易懂,也就是指某个内存单元在内存中的地址。


那么继续:
按下开机按钮后,CPU将会被唤醒,
CPU被唤醒的时候是一片空白的,它什么都没有,
所以它唯一知道要做的,就是从内存中的一个固定的地址n上
读取一个数字,并将它翻译成指令并执行,
然后再从下一个地址n+1中读取...如此反复.
我们提到的固定地址n,实际上它就是由硬件工程师预先设计的,
也就是说每次开机它都会从这个地址开始读取指令,并且执行后
读取下一个地址n+1的指令,
CPU就是这样按照顺序从内存中读取并执行指令的,
并且,一般工程师会在这个地址上开始写一段"开机程序",
他会做一些和初始化有关的事情,让接下来的
用户程序可以正常运行
但是我们知道内存单元是有限的,也就是说它总会读到一个头,
把地址读完,那该怎么办?
实际上存在一种叫做跳转(JMP n)的指令,它可以让CPU
从这个指令指定的一个地址开始重新顺序读取指令。
比如CPU执行了[JMP 450]30,那么CPU下一个要执行的
指令就是[...]30而不是[...]450了.(省略号表示内容省略)
这样我们就知道CPU是如何不断执行指令的了。


但是我们也希望CPU能够偶尔休息一段时间,
这时候关机按钮就派上用场了,
我们按下关机按钮后,CPU会以某种以后会讲的方式,
得知停机的请求,然后它会跳转到一个固定的地址p,
这个地址p也是工程师预先设计的,并且在p这边
写下"关机程序",用来为关机做一些准备,最终会导致CPU运行的结束,
CPU恢复空白状态,并且切断电源,等待下一次开机....
这就是CPU的一生(划掉)


因为这节文字有点多,所以做个小结:
CPU开机后从一个特定地址开始,按照单元地址顺序执行程序。
结束时会跳转到特定的关机程序。
(有的CPU没有关机程序,直接关机断电,这样也可能有丢失数据的风险)


还是给个例子:
假设我们设置的开机地址就是0,然后关机地址是810。


>>>开机
>>>
CPU:
执行[...]0
执行[...]1
执行[...]2
执行[...]3
.......


>>>关机
>>>
CPU:
执行[...]810
执行[...]811
执行[...]812
执行[...]813
.......
(直到切断电源)
===============================================================

楼主 savenseg  发布于 2019-03-16 13:29:00 +0800 CST  
===============================================================


【###======
【#CHAPTER[0]-0.5【计算机与外界交互的方法】
【###======
上节我们讲到计算机是怎么执行程序的,
但是计算机该怎么知道我们按下了开机按钮呢?
这就涉及到了计算机的输入/输出系统(以后简称IO系统)。
IO存在的目的就是让我们能够和计算机互动,
让计算机知道我们在干什么,也让我们知道计算机在干什么。


要实现IO系统,有好几个可行的模型。


例如:
给CPU提供两个指令IN n和OUT n,


IN n的作用是从一个固定的通往外界的数据线上截取数据,
并且把这个数据覆写到内存单元[...]n中。


OUT n的作用是把内存单元[...]n中的数据直接写到
另一个通往外界的数据线上。


这样我们只需要在外面监听OUT对应的数据线,
就可以在CPU执行OUT指令时知道CPU想发表的信息,
而CPU也可以在执行IN指令的时候,从IN对应的数据线上,
截获我们预先放置的数据,
这样我们就完成了一个与CPU系统的简单交互。


但是这个方法的缺点很明显:
它只能分别对两个数据线进行交互
(当然我们可以把指令修改成IN a,n这样的形式,
让它与编号为a的数据线交互,便可间接解决这个问题)
它占用了指令位(很多时候CPU的指令位很有限,只能定义不多的指令)
它需要牵额外的数据线到CPU处(当然其实MC里这个不是太明显的问题)
它不方便拓展增加交互的设备。


这种方法实际上比较原始,虽然在MC中会有时候这种方法更好用。
(实际上采用这种IO方法的计算机的模型是IO-CPU-RAM,与之前所提不同)




如上所述,这着实是一个蠢办法,所以我们引进一个新的解决方案:


将IO接口映射到内存单元中


这里有两个词可能对读者有些陌生:接口,映射。


在计算机中,接口是一个设备向外提供的口子,最简单的例子比如
有线鼠标的数据线头部的插头与计算机接入鼠标数据线的插槽,
这个插头和插槽便是两个接口,
插头是提供鼠标输入数据的接口,
插槽是接受输入数据的接口,
也就是说,接口是用来给两个东西交换信息的缺口,
当然要注意,接口不一定只用来接受信息,它还可能用来发出信息。


映射是一种改名换姓的思想,
比如说,我们把 王老菊 称为 老王 。
那么我们听到老王名字的时候,就会通过映射的办法把名字替为王老菊


老王 -> 王老菊


这个把一个名字换成另一个名字的东西叫做映射,
我们通常会用一个字母比如f表示一个映射,
并且在后面加个括号,也就是f()的形式,括号里面的东西是映射前
的东西,加上映射f()后,就是映射后的东西了,
比如y=f(7),这里的7就是我们对映射的输入,
而y就是映射的输出也就是f(7)


这样我们就可以把 老王 -> 王老菊 表示成f(老王)=王老菊
当然我们还得事先定义好这个映射,否则我们可能不知道它会怎么射的。


比如我们定义映射f,f的定义是f(x)=100*x,
这样的话f(10)=100*10=1000,f(0.5)=100*0.5=50。以此类推。


那么我们回到正题:"将IO接口映射到内存单元中"


先考虑怎么在内存中与外界交互:
假如这里有两根数据线A和B,
我们通过暴力手段,把数据线A焊接到内存单元[...]7上,
B焊接到内存单元[...]8上。
这样的话,如果我们向数据线A输入数据,那么内存单元[...]7的
内容会立即被改写,比如我们令A=6,那么立即有[6]7.
与此类似,如果CPU向[...]8写入9,变成[9]8,那么也立即有B=9。
这样便可在内存中进行交互IO,
但是向内存中强行焊几根线是毫无疑问的麻烦,


所以我们采用映射的办法,让CPU以为自己在从内存中读取数据,
实际上是在从数据线上读取数据:




我们先了解三个常识:


CPU会有三个接口,分别是:
地址接口,数据接口,指令接口。
然后RAM也有三个接口,分别是:
地址接口,数据接口,指令接口。(没错他们名字一样但是不要混淆)
CPU与RAM同名的接口相互连接交换数据,
CPU发,RAM就收;RAM发,CPU就收。
具体是这样滴:
CPU会把一个内存单元的地址放在自己的地址接口上,
这个地址就是CPU要读取或者覆写的内存单元的地址。
然后CPU会把指令放到指令接口上,
它可以是读取指令READ或者覆写指令WRITE,
然后RAM会分别从数据,地址接口接收到来自CPU的单元地址和控制指令。
首先RAM会根据地址接口上得到的单元地址确定接下来需要控制的单元,
它会立即定位这个单元,并且在接下来根据来自CPU的控制指令,
判断是要读取这个单元的数据还是覆写这个单元,
如果要读取,RAM会从这个单元中复制一份数据出来,并放到
数据总线上,让CPU获得,
如果要覆写,CPU则在发送地址和指令的同时还会发送一份数据
到数据接口上,这时候RAM会读取数据接口的数据,并且把它写入
目前定位的内存单元上。


了解了这么多,我们便开始正题:
我们该如何迷惑CPU?
CPU不受药物分子作用,但是它是个很诚实的憨憨。


我们只需要在CPU和RAM的三个接口中间,加一个称为映射器的结构,
这样,CPU发东西都会经过这玩意,
那么,我们可以在这个映射器中事先定义几个映射关系,
也就是说,把特定的内存地址映射到数据线编号上,
比如我们定义数据线编号S1被映射到内存单元100上,
那么CPU发送地址100到映射器的时候,映射器会识别到这个
地址,并且在出口把地址替换成S1,在后面的电路中,
内存不会响应对S1这个地址的操作,因为内存中不存在这个地址的单元,
但是这时候,数据线S1就可以识别到来自CPU的请求,
并且与CPU完成交互(由读取和覆写指令完成)。


可以画个图:
这里我们假设内存的地址范围是0~n,
映射到IO数据线的地址范围是n+1~n+9.


【内存RAM】
↑(如果地址属于0~n)
【映射器转发数据】←【CPU】
↓(如果地址属于n+1~n+9)
【IO数据线】(每个数据线实际上提供了一个自己的存储单元来存储数据)
===============================================================

楼主 savenseg  发布于 2019-03-16 15:06:00 +0800 CST  
===============================================================
【###======
【#CHAPTER[1]-1.1【图灵机与图灵完备】
【###======


这一节我们开始了解图灵机,
图灵机是什么?
图灵机是一种理想中的处理器模型,它拥有无限大的内存,
并且经过证明可以完成任何问题的计算。


这里引出了一个概念:
"图灵完备性"
如果一个处理器在拥有无限内存的情况下可以计算任何问题,
那么我们称这个处理器是图灵完备的。


我们可以证明一些相当怪诞的机器拥有这种图灵完备性,
比如生命游戏,蓝盾蚂蚁,或者是许多其它的东西。
它们的规则有时候可以简单的令人吃惊,
遗憾的是这些简洁的规则过于简化,以至于拥有极低的执行效率与
可编程性,所以我们一般都不会采用这些机器运行程序,
否则这会让大家都很苦恼。


如何判断处理器的图灵完备性?
只需要证明它与图灵机等价就行了,也就是说图灵机能做的事情,
它也能做。


有的时候我们不一定得强求处理器具备图灵完备性,
尤其是在嵌入式领域(嵌入式处理器是一种被设计用于
处理某些专门任务的处理器)中,但是设计一个通用处理器,
我们当然得让他具备这种特性,当然,在实际设计中,
我们会发现这种性质几乎是顺带的。


有关图灵机的更加详细的讨论与可计算理论有关,
事实上这种理论研究与我们的处理器架构设计的确存在着相当的距离,
因此在这里我们不会做出进一步的讨论。
但是不妨碍大家进一步的了解。
===============================================================

楼主 savenseg  发布于 2019-03-16 15:45:00 +0800 CST  
有人吗。。。

楼主 savenseg  发布于 2019-03-16 16:04:00 +0800 CST  
日哦,被吞了一个

楼主 savenseg  发布于 2019-03-16 20:10:00 +0800 CST  


直接上截图算了,百科链接自己百度二进制

楼主 savenseg  发布于 2019-03-16 20:19:00 +0800 CST  
===============================================================
【###======
【#CHAPTER[1]-1.4【一个CPU内部模型】
【###======
之前我们一直将CPU作为一个黑盒看待,
现在我们来研究它的内部构造,
CPU的结构被称为架构,架构与指令集的关系:
架构是处理器的结构,而指令集是这个结构所实现的功能.
那么来看一个简单案例:


这个简单案例中,CPU由这几个部分构成:


ALU(算术逻辑核心),GPRs(通用寄存器组),CU(控制器),CLOCK(时钟).
首先对这几个新名词做些解释:


##############################################################
ALU:ALU是CPU中的算数核心,它负责完成数据的计算功能,比如加法或者
减法,或者是其它一些计算功能,在执行运算指令的时候,指令的执行
会把操作数送往ALU里,然后再把ALU的运算结构送到要覆写到的单元,
比如ADD A,B。这个指令的执行过程是:
先把,A,B中的值送到ALU里,然后再指挥ALU完成加法运算,运算输出的
结果再被送到A中.
一般ALU至少会支持这些运算功能:
加,减,与,或,非,异或,移位.
也可以添加其它的功能,增强ALU的性能,
但是我们不必过于追求功能强大的ALU,因为很多事情本身就是
可以通过编程实现的,而且复杂的功能意味着更大更复杂的电路,
如果ALU不支持乘法,那么我们可以预先写一个乘法程序,然后在
每次需要算乘法的时候,调用这段程序,


这需要用到
指令对: [CALL n和RET] 或者 [INT n和RET]
做个简单介绍:


CALL n和INT n类似于JMP n,不同的地方在于CALL n执行时会将跳转
前的地址临时保存起来,
(可能被保存在某个特定的寄存器或者内存单元中)
随后跳转到起始地址为n目标代码段,被调用的代码段
结尾应当总是有一个RET指令,它的功能就是用我们临时保存的地址
返回到之前执行CALL n的指令的地址位置的下一位,
给个简单例子:


[CALL 30]0
[]1
[]2
...
[ADD A,B]30
[RET]31


如果CPU执行了[CALL 30]0,那么它会保存这个指令对应的地址,
比如这里[CALL 30]0这个指令所在单元的地址是0,
那么CPU会临时保存这个0,并且再将PC修改为30,就跟JMP做的一样,
然后跳转到的地方就是调用代码段了,
调用代码段是我们预先在内存中特定位置写好的一段,
会被反复使用的代码,这段代码实现的功能可能经常被用到,
这个案例中的调用代码段是:
[ADD A,B]30
[RET]31
只有两行代码,一个是ADD一个是RET.
CPU会执行ADD,然后接下来执行RET,RET的功能就是再次提取出我们
事先存储的地址0,然后返回CALL 30执行的地方.


在这段代码中处理器取指令的顺序是:
[]0->[]30->[]31->[]1
这里体现了JMP与CALL的区别:
如果我们用JMP做一个跳转,跳转后我们并不能返回原先执行JMP的
地方,而CALL可以.
INT类似CALL,这里暂不做详细讨论.
CALL这样的指令让我们可以预先保存一些特殊功能的代码段,
代码段会被反复调用.如果我们让这个代码段实现乘法计算,
比如我们让[]70开始是一段完成乘法计算的调用程序,
那么如果我们需要计算乘法,就只需要喊一句CALL 70,而不需要临时
再写一大段冗余的代码.
这样,对于ALU不支持的功能,我们都可以用调用代码段实现,
调用代码段的功能实际上要强得多,它能实现包括ALU不能实现的功能.


(在实际运用中,CALL n中的n和INT n中的n并不一定代表着内存单元
它们会通过一个预先设计好的映射表来查找调用代码段的位置
比如CALL 20,这个20是调用号,那么CPU首先从内存中某处事先
存好的调用映射表里查找,找到第20项,然后这个项对应的内容
就是20号调用程序的起始地址,映射表需要由程序员来提供,
如果你给这个计算机编写了一个操作系统,它就会由操作系统来维护,
维护这么个映射表有相当多的理由)
##############################################################


##############################################################
GPRs:GPRs是处理器内部的一组存储单元,例如我们之前介绍的R0到R31,
就是一组寄存器,每个寄存器都是标准的存储单元,但是他们的用途
存在差异,这是用法而不是电路结构决定的:比如说指令集里的某些指令
会将某个特定的寄存器作为判断条件,


比如把R31作为标志寄存器,
那么再提供一个标志跳转指令JMPF n,这个指令被定义的会专门检查
R3中1的值,再根据这个值判断是否修改PC的值(比如值不为0就[PC]<-n),
这里的PC又是一个特殊的寄存器,如果在这个案例中把R31作为PC寄存器,
那么每次CPU读取完指令都会自动给它的值+1,
并且JMP指令也会修改它的内容,寄存器还可以规定很多特殊用途,
具体统统取决于指令的设计.


寄存器组的一般用途就是在CPU内部临时存储数据,我们可以通过转移
指令MOV A,B交换寄存器与内存单元的内容,比如 MOV R1,[10],就把
内存单元[]10中的内容拷贝到R1中了.


这样的好处是能够减少CPU与RAM之间的交互,因为寄存器组就在CPU
内部,所以访问寄存器组常常会比访问RAM快相当多,


另一个好处是,寄存器名通常都不会很多,比如R0到R31,就只有32个,
但是如果是内存单元[]n,内存会有几千上万个地址,
这样执行MOV A,B的时候,如果A是寄存器对象,那么0到31就能
定位这个操作数的位置,而如果B是内存单元对象,那么可能就需要
0到16384,甚至更大的范围才能定位这个操作数的位置,
大的范围意味着大的比特,
比如MOV R0,R1可能长度只有16bits,但是MOV []30554,[]1110
的长度或许就是64bits,一个64bits都可以存4个16bits的MOV了。
(这里的指令是不定长的,也就是指令的长度不一定是统一的)
##############################################################


##############################################################
CU:CU就是CPU的控制器,它负责解析从RAM中读取出来的指令,并且
执行,除了执行指令,它还会做很多基本维护,比如给PC的值+1。
CU会控制数据的流向,比如让某个寄存器比如R7的值送往ALU中,
或者是让[]540中的值送往R4中,这些控制的时序都是由CU来完成的.
CU里会包括一个解码器,负责将CPU收到的指令翻译成
一步步的控制时序,


例如:
MOV [7],R0 (把R0的值覆写到[]7中)
CU会把R0的值写到数据接口上,然后
把地址7写到地址接口上,
然后在控制接口上写下覆写操作代表的编码,
这样RAM会收到这些东西,并且执行.
指令执行完后,CU还会让PC的值+1,也就是[PC]<-[PC]+1,
除了跳转指令那一类的指令,每个指令结束后都会发生PC+1.


再例如:
ADD R1,R2
CU会把R1和R2的值送到ALU,然后通过控制线通知ALU执行加法,
然后把ALU输出的结果覆写到R1中.
##############################################################


##############################################################
CLOCK:大家应该都知道每个CPU都有一个固定的周期时钟,
这个时钟每隔一段固定的时间就会发出一个脉冲,
这种稳定的节拍就像是心脏搏动的节律,指挥处理器有序地执行
指令,也就是所谓的 同步,相反的是 异步。
时钟发出的两个连续脉冲的间隔时间就是它的时钟周期,
就像你心脏两次连续跳动之间有一个最小的时间,
那个就是它的(最小)周期.
可以用周期冲激函数描述它,当然这不是信号系统课不用关心那么多.
一般CPU的指令周期存在差异,不同指令,不同情况指令占有的时钟周期
都不同,比如MOV R1,R2可能要消耗2周期的时间执行,
而ADD R1,R2会消耗三周期。每个指令消耗的周期数可能不同,
消耗的周期数乘与时钟的周期,就可以得到一个指令的执行时间:


】】】指令执行时间=(指令消耗的周期)*(一个时钟周期的长度)【【【


(这个公式很有用)


用这种公式可以简单分析一些程序的运行时间,
另外指令的周期有时也是不定的:
比如MOV R1,[]10501.
从内存中读取数据会花很多时间,并且不是固定的,
可能读取[]10要1秒,读取[]204就要2秒了,具体有很多因素.
这类指令,不能直接分析他们的执行时间.
##############################################################


上面我们简单介绍了ALU,GPRs,CU,CLOCK这几个名词的含义,
而他们在CPU里是通过各种数据线和控制线链接的,
这里给个例子:(不同CPU中模块的连接方式可能不同)


其中红色的是控制线,蓝色的是数据线,紫色的也是,箭头标识了数据的方向.
那个分路器的具体功能是,分路器有一个输入O个两个输出A和B,然后
还有一个控制线C,当控制线C=1时A和O链接,C=0时B和O链接,就是这样
另外最后说明一下CPU的位数:
CPU的位数一般来说就是ALU的输入或者GPU一个单元的位宽。
大家一般喜欢取8 16 32 64...这样的倍数。
===============================================================

楼主 savenseg  发布于 2019-03-17 09:18:00 +0800 CST  
干哦,百度疯狂删贴

楼主 savenseg  发布于 2019-03-18 10:05:00 +0800 CST  


这次依旧是图片,而且得分多层发了

楼主 savenseg  发布于 2019-03-18 10:06:00 +0800 CST  


楼主 savenseg  发布于 2019-03-18 10:07:00 +0800 CST  
下一节超长,看完下一节你就会造CPU了.所以为什么没人啊啊啊啊啊啊啊啊啊啊啊

楼主 savenseg  发布于 2019-03-18 13:31:00 +0800 CST  
因为太长得分段发..尴尬

楼主 savenseg  发布于 2019-03-18 13:38:00 +0800 CST  
===============================================================
【###======
【#CHAPTER[1]-1.6【设计一个简单CPU-架构设计】
【###======
我们在上节确定了这个处理器要使用的指令集,
它是一个长度统一32bit,存在两种格式,
支持R0到R31共32个寄存器,包括15条指令的指令集.


我们可以把指令按功能分成几类:
算数指令:ADD,SUB,AND,OR,NOT,XOR,SL,SR
跳转指令:JMP,CALL,RET
分支指令:JMPZ,JMPP
转移指令:MVIN,MVOT,MOV


我们需要先确定CPU内部需要的功能模块:
我们将CPU内部主要划分为:


ALU,GPRs,CU,地址接口CPU_ADDRESS,
数据接口CPU_DATA,控制接口CPU_CONTROL.


这六个模块.


我们希望ALU能够完成算数,
而GPRs充当寄存器的功能,
CU则负责分析执行指令,
而剩下的三个接口相当于处理器的插口,可以与外界链接.


我们先来确定ALU的设计:


ALU模块提供四个接口,分别是:
接口ALU_A,接口ALU_B,接口ALU_OT,接口ALU_C.


ALU的功能描述是这样的:
根据接口C的输入选择ALU的运算功能,
然后对接口A,B中的数据执行运算,
运算结果输出到接口OT中.


我们已经知道这个指令集有一个叫funct的端是决定算数功能的,
所以执行算数指令的时候,我们会把指令中的funct段直接送入端口C,
以让ALU选择算数功能,
然后会将两个源寄存器中的数放入A,B.并且在运算结束时把结果从
端口OT覆写到目标寄存器中.


那么端口ALU_C与ALU的运算模式间的关系应该是这样的:
ALU_C=100000对应加法模式,这时候ALU_OT=ALU_A + ALU_B
ALU_C=100001对应减法模式,这时候ALU_OT=ALU_A - ALU_B
ALU_C=100010对应AND模式,这时候ALU_OT=ALU_A AND ALU_B
ALU_C=100011对应OR模式,这时候ALU_OT=ALU_A OR ALU_B
ALU_C=100100对应XOR模式,这时候ALU_OT=ALU_A XOR ALU_B
ALU_C=100101对应SL模式,这时候ALU_OT=ALU_A SL ALU_B
ALU_C=100110对应SR模式,这时候ALU_OT=ALU_A SR ALU_B
(至于怎么用电路具体实现这些运算,以后会讲(数字电路))


然后是GPRs:
这个指令集确定了32个通用寄存器组:R0到R31,
寄存器单元与内存单元差不多,我们只需要在CPU内部,
提供一个包括32个内存单元([]0到[]31)的存储器就可以了.


GPRs会提供GPR_IN,GPR_OT,GPR_CH,GPR_ADR这四个接口,
GPR_IN是GPRs的数据输入,GPR_OT是GPRs的数据输出,
GPR_CH是GPRs的功能选择与执行接口,
GPR_ADR,就是GPRs中的存储器的地址输入.


功能描述是这样的:
GPRs内部有32个存储单元,分别是[]0到[]32.
GPR_CH可以是三种值:
GPR_CH=00,这时什么也不做
GPR_CH=01,这时将GPRS_IN中的值覆写到[]n,n=GPR_ADR.
GPR_CH=10,这时将[]n中的值复制到GPRS_OT上,n=GPR_ADR.


而CU的功能则是向这些模块上的接口和CPU的接口发送控制数据,
或者控制这些接口之间的连接.
上面我们提到的所有接口分别是:


CPU_ADDRESS,CPU_DATA,CPU_CONTROL;
ALU_A,ALU_B,ALU_OT,ALU_C;
GPR_IN,GPR_OT,GPR_CH,GPR_ADR.


可以把它们分成"数据接口","控制接口"两种接口类型,
CU会向控制接口发送控制信息,指挥模块工作.
CU还会指挥数据接口之间数据的转移,让某个
数据接口里的数据转移到另一个数据接口里,
或者让数据接口里的数据变成什么.

楼主 savenseg  发布于 2019-03-18 13:40:00 +0800 CST  

楼主:savenseg

字数:34097

发表时间:2019-03-16 19:01:00 +0800 CST

更新时间:2019-09-05 16:17:56 +0800 CST

评论数:350条评论

帖子来源:百度贴吧  访问原帖

 

热门帖子

随机列表

大家在看