|||
前面给出的原型CPU实际只能够执行顺序结构的程序。计算机CPU能够替代人脑工作,需要有判断分析的功能,还要能够循环地考虑问题。这就是程序设计的分支与循环。这一部分我们将进入复杂一些的CPU结构设计,如果你的基础不够,就要多下一点功夫了。
判断是智能的标志,计算机能够实现程序运行的有条件跳转,就是智能的表现。本节介绍的能判断计算机可以完成数据的自动输入和地址的不连续变化,具有了一定的判断能力,能够实现跳转和循环结构的程序设计。
人类进行判断要依据某种变化的信息,计算机实现判断也要依靠某种变化的标志信号,实现判断的计算机必须提供这种标志机制。
这里给出的电子计算机是在前面加减运算计算机的基础上改造的,它的结构如图6‑1所示。为了实现程序运行中数据的输入,结构中将EROM换成了RAM。RAM有一条复位线Clr可以使所有的存储单元的值为0。前面的加减运算计算机只能从存储器的0000号单元开始执行指令,执行程序的方式只能是顺序的,不能改变顺序,不具有灵活性。这个计算机将行波计数器换成了程序计数器,目的在于能够实现程序的跳转和循环。程序计数器PC有L门,能够通过L门控制数据的输入,实现程序指令的不连续执行。结构中增加了输入寄存器IN,它可以从外部接收数据,然后送到RAM和其他寄存器。另外,为使该计算机有一定的判断能力,还为累加器A的值为0和为负设置了标志,A为负数时由线NF=1标出,A为0时由线ZF=1标出,这样可以根据这两条线的值实现程序的有条件跳转。
显然这台简单的计算机的计算机控制字已经长了许多,由于增加了控制线,使原来的加减运算计算机的12位计算机控制字扩展成了15位:
LpEpCpLmMeIOLiEiEnLaEaEuSuLbLo
由于输入寄存器IN的数据装入不是由控制器CON进行管理的,所以输入寄存器的控制线Ln不包含在这个计算机的控制字当中。
图6‑1 能判断计算机的结构
为了判断运算的结果,本计算机设计了判断累加器A中内容是0还是负数的识别线。图6‑2中,ZF是累加器A的所有数据位的或非门电路的输出端,它的值能够确定A中的数据是否为0。NF是累加器A的数据最高位的输出端,可以用它来确定A中的数是正数还是负数。这两条线都是为跳转指令准备的。由逻辑电路可以分析出,ZF=1表示存放在累加器A中的数据是一个0;NF=1表示存放在累加器A中的是一个负数。可见通过ZF、NF可以知道累加器A的状态。
图6‑2 标志线
定义6‑1 能够标明设备状态的线叫标志线。
ZF,NF就是标志线。标志线并不是机器的控制字,但它们是确定控制矩阵的依据,直接成为控制矩阵的自变量,属于自变量集中的元素,它们能对控制矩阵的输出端进行相应的逻辑控制。
根据标志线的定义可以知道,指令线也是标志线的一种。
计算机中的标志线一般都用1表示确认的状态,用0表示对那种状态的否定。
为了使问题简单,能判断计算机结构增加了一个输入数据寄存器IN。输入数据寄存器IN的E门是主管向总线输送数据的,而L门则是主管从外部接收数据的,不受CPU的管理。假设输入数据寄存器IN的L门一打开就有数据进入,这些数据是事先准备好的。实际当中数据如何进入到数据寄存器,等到讲键盘缓冲区的时候再阐述。
能判断计算机是具有条件判断功能的计算机设计,主要表现为依据一定的标志线信息,来决定后面的指令应该执行那一条。
根据需要,能判断计算机的指令比加减运算计算机的指令多设计了6个,在此将全部指令也列出一张表来说明这这些指令的设计内容(见表6‑1)。
表6‑1 指令代码设计
功 能 | 助记符 | 操作码 |
将数据装入当前存储单元 | LOD | 0000 |
将存储单元R的内容送到累加器A | LDA R | 0001 |
将存储单元R的内容与累加器A相加,结果送累加器A | ADD R | 0010 |
将累加器A与存储单元R的内容相减,结果送累加器A | SUB R | 0011 |
将累加器A的内容送到存储单元R | STR R | 0100 |
跳到R单元取指令 | JMP R | 0101 |
如果累加器A的值是0则跳到R单元取指令 | JZ R | 0110 |
如果累加器A的值为负则跳到R单元取指令 | JN R | 0111 |
将存储单元R的内容输出 | OUT R | 1000 |
读入数据并送到存储单元R | IN R | 1001 |
停机 | STP | 1111 |
LOD称为装入指令,它的作用是将8位的外部数据放入本指令所在的存储单元。由于这个地址是隐含的,故其指令格式中不要操作数。
这里把装入指令LOD的代码编为0000是因为存储器RAM带有Clr端,在开机时会将全部存储器单元的数据都变成00000000,使每一个存储单元就都放置了LOD指令,这样通过LOAD可以将和存储器一样大小程序和数据一次性放入存储器。
有了指令LOD,在编程序时就不必用手去拨动EROM的开关了,可以按照存储器的形式将一条条的指令和数据书写好,放在某个外部介质上,开机时就会一次性地被读到存储器RAM中来,这样就能完成程序的自动输入任务。
为了能够自由地将输入数据放在指定的存储单元,这里又设计了数据输入指令IN,该指令可以在操作码的后面直接指出存储单元的地址,这样就可以将数据输入到RAM存储器的指定地方。
为了能够存放运算的结果,能判断计算机还设计了将累加器A的内容送到指定存储单元的指令STR,存储单元的地址作为操作数写在指令操作码的后面。
该计算机的结构已经使它具有逻辑判断的功能,于是就设计了两条按照一定条件改变程序执行顺序的指令,这就是有条件跳转指令JN和JZ。JN的意思是当累加器A的内容是负数时发生跳转,转移的地址由JN后面的操作数指出,形式是“JN R”。JZ的意思是当累加器A的内容是零时发生跳转,转移的地址也由JZ后面的操作数指出,形式是“JZ R”。
为了灵活地按照程序设计者的意愿进行程序执行,还设置了无条件跳转指令JMP,要跳转执行的下一条指令的地址由JMP后面的操作数指出,形式是“JMP R”。
条件跳转
从能判断计算机的结构可以看到,如果要改变指令的执行顺序,那么应设法将下一条要执行的指令的存储地址放在程序计数器PC中。根据跳转指令的格式,当跳转指令被放在指令寄存器IR后,就可以将IR的低4位传送给PC来达到跳转执行指令的目的(见图6‑1)。在这个过程中,涉及到两条控制线Ei和Lp。如果无条件产生跳转,那么应该有Ei=1,Lp=1。但是如果是条件转移,Ei、Lp是否为1还要看条件,也就是NF和ZF两条标志线的具体值。
在加减运算计算机中已经提到过的指令,在这个能判断计算机中都有,它们的例行程序稍有变动。因为这里使用的是随机存储器RAM,如果需要访问RAM,就必须令Me=1,这一点在它们的例行程序中都必须得以体现。在EROM的使用中没有提到块选择线Me,那是因为EROM的输出有输出控制线Er管理是否向总线输出,EROM没有输入,不会引起总线数据的混乱。在块存储器组织的RAM中,使用时还必须要求存储器选择线enable=1。
为了分析和设计简单,指令可以分成几部分来研究它们的例行程序。
原指令的例行程序
加减运算计算机的指令在这个计算机中,例行程序略有变化,其中Er控制线变成了Me控制线,还有输出指令不再是将累加器A的内容输出,而是采用了更加灵活的将存储单元内容输出的形式。
为了使指令过程分析简化,以后值为0的控制线不写出,而只将值为1的控制线用等式表达出来。
指令OUT R的例行程序如下:
(1) Ep=1 Lm=1 (PC →MAR)
(2) Me=1 Li=1 (RAM →IR)
(3) Cp=1 (PC+1)
(4) Ei=1 Lm=1 (IR→MAR)
(5) Me=1 Lo=1 (RAM→O)
(6)
OUT R的第4拍是将指令寄存器IR的输出送到地址寄存器MAR,第5拍将RAM的输出送到输出寄存器O。
新增指令的例行程序
这个计算机新增加的指令LOD、JMP、JZ、JN、STR、OUT、IN的例行程序仍然是6拍,它们的取指周期为:
(1) Ep=1 Lm=1 (PC →MAR)
(2) Me=1 Li=1 (RAM →IR )
(3) Cp=1 (PC+1 )
下面分别给出新指令例行程序的执行周期。
(4) Me=1 IO=1 En=1 (IN →RAM)
(5)
(6)
需要指出的是,在LOD的执行周期中地址寄存器MAR的值一直都没变,故从输入寄存器读到的指令或数据,会放回LOD指令的那个存储单元。
(4) Ei=1 Lp=1 (IR的低4位送到PC)
(5)
(6)
A中内容为零转移指令 JZ R 的执行周期
(4) 如果ZF=1,那么Ei=1 Lp=1 (A中内容为零IR的低4位送到PC)
(5)
(6)
A中内容为负转移指令 JN R的执行周期
(4) 如果NF=1,那么Ei=1 Lp=1 (A中内容为负IR的低4位送到PC)
(5)
(6)
(4) Ei=1 Lm=1 (IR→MAR)
(5) Ea=1 Me=1 IO=1 (A→RAM)
(6)
(4) Ei=1 Lm=1 (IR→MAR)
(5) En=1 Me=1 IO=1 (IN→RAM)
(6)
IN指令和LOD指令的不同之处是,LOD指令是将数据回送到原来LOD指令所在的存储单元,而IN指令是将数据送到指令操作数所指出的那个存储单元。
6.1.4. 能判断计算机控制器控制矩阵分组
计算机控制矩阵的设计是很复杂的,但如果新设计的计算机只是在原有的计算机中增加了设备,新增加了一些指令,并且原有的指令例行程序没有变化,那么只要设计增加的一部分指令的控制矩阵,然后将新增的控制矩阵与原控制矩阵连接。具体的连接方法,是把重复出现的控制线用或门连接,新增的控制线添加进去,这样就可以得到新设计计算机的控制矩阵。
能判断计算机的指令系统中虽然包括加减运算计算机的全部指令,然而例行程序都有一定的变化,所以不能够采用增添设计控制矩阵的方法。但为了减轻控制矩阵整体设计的压力,采用分块设计会使设计工作变得容易,并且适合多人参与的团队作战。表6‑2和表6‑3就是将指令分成两部分,分成2组的例行程序真值表,通过这两个真值表可以设计出控制矩阵的两部分。为了方便直接书写表达式,节拍前面增加一个字母“p”。
表6‑2 原指令的例行程序
指令 | 机器动作 | 节拍 | Cp | Ep | Lm | Me | IO | Li | Ei | La | Ea | Su | Eu | Lb | Lo |
| PC→MAR | p1 |
| 1 | 1 |
|
|
|
|
|
|
|
|
|
|
RAM→IR | p2 |
|
|
| 1 |
| 1 |
|
|
|
|
|
|
| |
PC+1 | p3 | 1 |
|
|
|
|
|
|
|
|
|
|
|
| |
LDA R | IR→MAR | p4 |
|
| 1 |
|
|
| 1 |
|
|
|
|
|
|
RAM→A | p5 |
|
|
| 1 |
|
|
| 1 |
|
|
|
|
| |
| p6 |
|
|
|
|
|
|
|
|
|
|
|
|
| |
ADD R | IR→MAR | p4 |
|
| 1 |
|
|
| 1 |
|
|
|
|
|
|
RAM→B | p5 |
|
|
| 1 |
|
|
|
|
|
|
| 1 |
| |
A+B→A | p6 |
|
|
|
|
|
|
| 1 |
|
| 1 |
|
| |
SUB R | IR→MAR | p4 |
|
| 1 |
|
|
| 1 |
|
|
|
|
|
|
RAM→B | p5 |
|
|
| 1 |
|
|
|
|
|
|
| 1 |
| |
A-B→A | p6 |
|
|
|
|
|
|
| 1 |
| 1 | 1 |
|
| |
OUT R | IR→MAR | p4 |
|
| 1 |
|
|
| 1 |
|
|
|
|
|
|
RAM→O | p5 |
|
|
| 1 |
|
|
|
|
|
|
|
| 1 | |
| p6 |
|
|
|
|
|
|
|
|
|
|
|
|
|
表6‑3 新增指令例行程序
指令 | 机器动作 | 节拍 | ZF | NF | Ea | Cp | Ep | Lp | Lm | Me | IO | Li | Ei | En | Lo |
| PC→MAR | p1 |
|
|
|
| 1 |
| 1 |
|
|
|
|
|
|
RAM→IR | p2 |
|
|
|
|
|
|
| 1 |
| 1 |
|
|
| |
PC+1 | p3 |
|
|
| 1 |
|
|
|
|
|
|
|
|
| |
JMP R | IR→PC | p4 |
|
|
|
|
| 1 |
|
|
|
| 1 |
|
|
| p5 |
|
|
|
|
|
|
|
|
|
|
|
|
| |
| p6 |
|
|
|
|
|
|
|
|
|
|
|
|
| |
JZ R | IR→PC | p4 | 1 |
|
|
|
| 1 |
|
|
|
| 1 |
|
|
| p5 |
|
|
|
|
|
|
|
|
|
|
|
|
| |
| p6 |
|
|
|
|
|
|
|
|
|
|
|
|
| |
JN R | IR→PC | p4 |
| 1 |
|
|
| 1 |
|
|
|
| 1 |
|
|
| p5 |
|
|
|
|
|
|
|
|
|
|
|
|
| |
| p6 |
|
|
|
|
|
|
|
|
|
|
|
|
| |
STR R | IR→MAR | p4 |
|
|
|
|
|
|
|
|
|
|
|
|
|
A→RAM | p5 |
|
| 1 |
|
|
|
| 1 | 1 |
|
|
|
| |
| p6 |
|
|
|
|
|
|
|
|
|
|
|
|
| |
IN R | IR→MAR | p4 |
|
|
|
|
|
| 1 |
|
|
| 1 |
|
|
IN→RAM | p5 |
|
|
|
|
|
|
| 1 | 1 |
|
| 1 |
| |
| p6 |
|
|
|
|
|
|
|
|
|
|
|
|
| |
LOD | IN→RAM | p4 |
|
|
|
|
|
|
| 1 | 1 |
|
| 1 |
|
| p5 |
|
|
|
|
|
|
|
|
|
|
|
|
| |
| p6 |
|
|
|
|
|
|
|
|
|
|
|
|
|
控制矩阵设计
这个能判断计算机的控制矩阵完全可以像加减运算计算机那样来设计出来,表6‑2表6‑3有底纹的部分变量属于自变量,由表6‑2可得:
Cp=p3
Ep=p1
Lm=p1+p4(LDA+ADD+SUB+OUT)
Me=p2+p5(LDA+ADD+SUB+OUT)
Li=p2
Ei=p4(LDA+ADD+SUB+OUT)
La= p5·LDA+p6(ADD+SUB)
Su=p6·SUB
Eu=p6(ADD+SUB)
Lb=p5(ADD+SUB)
Lo=p5·OUT
这些函数的逻辑电路如图6‑3所示。
图6‑3 控制矩阵一组
由表6‑3可得:
Ea=p5·STR
Cp=p3
Ep=p1
Lp=p4(JMP+ZF·JZ+NF·JN)
Lm=p1+p4·IN
Me=p2+p5(STR+IN)+p4·LOD
IO= p5(STR+IN)+p4·LOD
Li=p2
Ei=p4(JMP+JZ+JN+IN)
En=p5·IN+p4·LOD
这些函数的逻辑电路如图6‑4所示
图6‑4 控制矩阵二组
根据逻辑等式A+A=A知道,以上两组逻辑函数中,完全相同的函数只在一组里表示出来即可,因而Cp、Ep、Li在后面一组中可以不必设计电路
控制器
这台能判断计算机的控制器如图6‑5所示,指令译码器译出的指令线有11条,除去STP还有10条。10条指令线、6条节拍线和2条标志线,自变量共有18条线,其中标志线ZF、NF只对控制矩阵二组起作用。
图6‑5 能判断计算机控制器电路
对于分组进行控制矩阵设计的方法,最后组织在一起的时候不要忘记,同名输出端要用或门组织成一个输出端。
能判断计算机控制器的工作过程,与加减运算计算机的控制器的工作过程基本一样,读者可以自己叙述整机的运行过程。
能判断计算机已经有了条件跳转的指令,于是可以利用跳转指令和条件跳转指令设计一些分支程序和循环程序了。
前面的例题中,曾用括号将数值括起来表示该数值的地址,其实可以用某种标识符来表示某一个存储单元的地址。
定义6‑2 在程序设计中表示可以存放数据的存储单元的标识符叫变量。
在编程中,有时仅仅是为了指明某一个暂时还不知道的存储单元的位置,这时也使用符号,这个符号后面要加上冒号以示与变量的区别。
定义6‑3 在程序设计中,只用来指示存储单元位置的符号叫标号。
标号和变量在后面的汇编程序设计中经常会用到。另外,在汇编程序设计中,一般用以“ ;”开始的部分来说明程序的功能,分号后面的部分是注释。
【例6‑1】 编程计算前n个自然数的和。
此例题可以从第n个自然数开始向1的方向求和。设置变量N放置自然数n,变量ONE放置1,变量和SUM放置最后的结果,SUM的初值是0。根据本计算机的指令系统写出的汇编程序如下,存储器分配如图6‑6所示。
START: | LDA | N | ;N→A |
| JZ | EXIT | ;N值为0跳转 |
| ADD | SUM | ;SUM+N→A |
| STR | SUM | ;A→SUM |
| LDA | N | ;N→A |
| SUB | ONE | ;N-1→A |
| STR | N | ;A→N |
| JMP | START | ;循环执行求和 |
EXIT: | OUT | SUM | ;输出结果 |
| STP |
| ;停止 |
这个程序先要进行编译,形成二进制代码后,才能放在存储器中执行。为了说明问题方便,这里就用汇编形式加以说明。程序和数据的存储器分配如图6‑6所示,这是一个逻辑分配,实际应将二进制代码在输入设备上放置好,开机时一次性装入存储器执行。
怎样分配存储器?一般过程是先设计一个与存储器同样大小的逻辑空间,在逻辑空间上从前向后的安排每条指令,在此过程中确定标号的位置。将指令分配之后,可以在没有占用的存储单元放置数据,从而确定出变量的位置。
图6‑6 存储器分配
假如已经像图6‑6那样安排好了二进制程序,现在如何把它放在RAM中执行呢?本计算机是采用如下的方法来完成的。
当电源打开之后,Clr瞬间为1,于是将各个设备进行了初始化。初始化的结果使RAM的每一个单元的值都是“00000000”,PC=0,环行计数器的值是“000001”。于是时钟启动时就开始执行0号单元的LOD指令。由于送到MAR的地址在后面的指令执行节拍中没变化,故读入的内容被写在0号单元中。此后由于PC自动加1和节拍循环的结果,使得16个存储单元像图6‑6那样装好的程序和数据,从而完成了装填工作。当将最后一个存储单元的内容处理完成之后,PC的值又回到了0,再一次去取0号单元的指令,就开始执行程序了。
乘法程序
虽然这台计算机的运算器只能做加减法,但可以设计程序让它能够完成乘法和除法。
【例6‑2】 编程求整数M N的积。
仍然假定输入的数据M 、N不会使结果产生溢出。乘法的问题可以用加法实现,具体思想是把M×N看作N个M的和。
此程序除了变量M、N之外,还要用到变量ONE和存放结果的变量RESULT,结果变量RESULT的初值是0,ONE=1。
| IN | M |
|
| IN | N | ;输入M、N |
LOOP: | LDA | N | ;N→A,用N作循环计数 |
| JZ | EXIT | ;若A为零,结束程序,跳转 |
| SUB | ONE | ;否则,N-1→A |
| STR | N | ;A→N |
| LDA | RESULT | ;RESULT→A |
| ADD | M | ;RESULT+M→A |
| STR | RESULT | ;A→RESULT |
| JMP | LOOP | ;循环执行,直到满足条件结束 |
EXIT: | OUT | RESULT | ;输出结果 |
| STP |
| ;停止 |
几乎同样的编程可以求得M/N的结果。由【例6‑2】看到只做加减法的计算机可以通过相应的程序设计,而达到实现乘除法运算。因此也就不难理解“软件是硬件的完善扩充和发展”这句话的涵义。
在计算机编程时,人们常用流程图来说明程序的运行结构。从设计的几个汇编程序中,能够看到执行的指令之间的顺序关系基本有三种,一种是先后的顺序结构,一种是分支结构,还有一种是循环结构。
程序中的这三种结构用图来表示,就是图6‑7所示形式。图中矩形框表示操作,菱形框表示条件,条件成立用“Y”标注,不成立用“N”标注,线表示流向,一般上面是入口,下面是出口。
图6‑7(a)是顺序程序结构,所表达的语义是:A操作完成之后,接着完成B操作。图6‑7(b)是分支程序结构,所表达的语义是:条件成立,从“Y”执行A操作,不然从“N”执行后面的操作。图6‑7(c)是循环程序结构,所表达的语义是:条件成立,从“Y”执行A操作,然后返回到条件,再次判断进入循环;如果条件不成立,执行从“N”执行后面的操作。
图6‑7 程序流程基本结构
在进行程序设计的时候,可以先不去考虑具体的指令,集中精力思考操作的相互关系,用流程图表达出来,然后再用具体的指令书写成汇编程序。实际上这种方法在较大的程序设计中是一种有效的手段。作为例子,将上面的两个例题的流程图画出(见图6‑8)。
例题【例6‑1】的详细流程图是将每一个指令的操作都画出了操作框(图6‑8(a)),实际上完全可以将一个完整的动作画成一个操作框,这样就可以得到简单一些的流程图(见图6‑8(b)),后者比起前者来,语义表达自然清楚,也比较简练。
图6‑8 程序流程
例题【例6‑2】的求MN乘积的流程图,就可以应用简单的画法给出,结果如图6‑8(c)所示。实际的流程图就常用自然的语言来描述。操作框有时可以代表一个简单的操作,也可以表示一个很复杂的操作,甚至代表一个程序。对于操作框,需要时可以再用流程图将复杂的操作过程画出来,程序设计的子程序调用问题,就使用这种方法在流程图中表示。操作框的层层深入,可以作到程序描述的由粗到细,有利于程序的结构化设计。
Archiver|手机版|科学网 ( 京ICP备07017567号-12 )
GMT+8, 2024-12-22 09:20
Powered by ScienceNet.cn
Copyright © 2007- 中国科学报社