指令系统

PCOM的CPU能够理解并执行的指令是具有32位字长的指令,它区分为操作码和操作数,如图4.9所示。操作码表示指令的种类,操作数则是直接或间接表示的被运算的数据。PCOM处理的数据,或为32位带符号的整数,或为逻辑值。在PCOM内进行处理时,设逻辑0为整数的0.逻辑1为1。PCOM的指令有下列19种,它们的集合称作指令系统。虽然PCOM的指令系统非常贫乏,但对于完成本章的任务来说已经足够了。

(1)pusha,popa,pushb,popb

(2)mul,div,add,sub,not

(3)ujp,fjp

(4)·cup,ent,ret,reti,eni,dsi

(5)ior,iow

(1)中的指令,或者表示从堆栈中取出数据,或者表示往堆栈中存入数据。(2)中的指令表示对堆栈中的数据作何种运算。

(3)中的指令表示产生程序的分支,(4)为调出或中断子程序(将

步骤(procedure)和函数(function)结在一起,称为子程序)时所必须的指令。(5)为IO设备的控制指令、下面我们详细介绍这些

指令

 

op

d

d₂

pushaaddr

01

0

addr

Popaaddr

02

0

addr

pushblevel,addr

03

level

addr

popblevel,addr

04

level

addr

ul

05

0

0

div

06

0

0

add

07

0

0

aub

08

0

0

not

09

0

0

ujpaddr

0A

0

addr

fjpaddr

0B

0

addr

cuplevel,addr

0C

level

addr

entlevaz

0D

0

lcvac

ret

0E

0

0

reti

0F

0

0

enl

10

0

0

dsi

11

0

0

ioraddr

12

0

0

iowaddr

13

0

0

 

图4.9PCOM的指令集

图中level,addr,levar表示整数

指令的作用和它们在实际程序中的使用方法,此外,PCOM中用到

的程序语言是PASCAL语言和汇编语言。

(1)pusha(op=1)addr,popa(op=2)addr

设接在pusha后面的值addr为地址,这个地址中的数据存放在堆栈中,设接在popa后面的值为地址,从堆栈中取出的数据存入这个地址,

例4.1在图4.10中,pusha123和popa124是从地址2开始顺序存人的,设在地址123中存放着数据41(H)。如果执行pusha123,则sp的值减1,并且将地址123中的数据写入p指示的地址中(压入堆栈)。其次,如果执行popa124,则sp指示的地址中的数据,将被写入地址124,且sp的值增加1(从堆栈中取出)。

(2)pushb(op一3)level,addr,popb(op=4)level,addr

根据pusbb和popb后面的两个值level和addr计算地址,pushb表示向堆栈存人数据,popb表示从堆栈中取出数据。level表示倒回静连接的次数,addr表示从

一帧程序系统最前面开始计算的相对地址。因为这个地址的计算方法与子程序的调出方式密切相关,所以在介绍指令cup时,将详细进行介绍.

(3)mul(op=5,积),diy(op=6,商),add(op=7,和),sub(op=8,差)

若sp指向某一地址,则对该地址的下一个地址中的数β,a(整数)进行计算:α×β(mul),α÷p(div),α+p(add),a一β(sub),然后sp增加1,并且在sp指示的地址中写入计算结果。

例4.2图4.11表示10+20×30的计算过程,程序从地址2依次写入框图内。执行三次pusha将数据压入堆栈.执行mul则对被压人堆栈上部的两个数据进行乘法运算14(Hj×1EcH)一258(H)。执行add,求与A(H)的相加结果262cx)。

(4)not(op=9,否定)

设sp指示的地址中的数据为逻辑值,这时如果是0,则变为1,如果是1,则变为0.


捕获.JPG

例4.3在图4.12中,堆栈的最上方被压入了逻辑值0。如果执行地址2中的指令not,则0变为1,sp的指示地址不变。

捕获.JPG

捕获.JPG

(5)uip(op=A(m)addr,fip(op=B(μ)addruip是将其后续值addr压人pc,然后跳转到这个地址的指令。fip是将压入到堆栈最上面的数据从堆栈中取出,当这个数据为逻辑0(false)时,跳转到fip后面的地址,当这个数据为逻辑1时,执行fjp的下一条指令。

例4.4在图4.13中,从地址2开始写入程序。当执行ujp4

捕获.JPG

时,无条件地跳到地址4.因为在地址4中装有fjp,所以取出压入到堆栈中的数据进行检验,因为是逻辑0,故跳到地址6.

(6)cup(op=Ccm)level,addr,ent(op=Dcm)lcvar,ret(op=E(H)这三条指令是调出子程序时使用的,它们具有再度返回调出程序块构造的能力,是一种像PASCAL,那样的高级语言目的指令。

子程序的调出现在我们来研究PASCAL的块状构造。PASCAL程序是由程序标题(programheading)和程序块(block)构成,如图4.14所示,程序块以label,const,type,var,procedure,function作为初始说明,并且用定义部分和begin,end环绕的复合条文共同构成。最后,在大的程序块中进一步包含某些小程序块。最外侧的程序块级数为0,0级程序块中的procedure和function部分的描述程序块为1级,……按照类似方法,可依次确定级数。例如在图4.15中,程序块A为0级,B,F为1级,C,G为2级,D,E为3.级。某一程序块中的描述和定义的变量名和过程名等仅在该程序块内有效。例如pi这个过程名,因为是在程序块A中描述的,所以可以从程序块A内,进而可以从程序诀A,B,

捕获.JPG

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21


programexample(output);

vara:real;

procedurepl;

vara:integer

begin

writeln(a);a:=2

end;

procedurep2;

yara:real;

begin

a;1.35;

writeln(a)

end;

bea(g)3.0;

pI

p2;pl;

writeln(a)end.


(执行结果)1077936128

1.35000E+001068289229

3.00000E+00


(因为第8行的a未被初始化)

 

(因为第6行的a未被初拍化)


 

在描述该名称的程序块内有效,所以在图4.15的程序块E内,过程p1(在程序块内描述)、p2(在程序块B内描述)、p3(在程序块内描述)均可以被调出来。此外,在E内还可以调出它自身内的p4

下面是一个求阶乘的程序,它是一个有代表性的例子。

这是一个计算01,11,21,3!,41551的程序。这里值得注意的是,除了fact(0)情况外,定义为fact的函数值不能立即确定。这就是说,当函数的自变量i为0时,函数的值为1,但在除此以外

1prograrnexample(output)

2vari:integer

3functionfact(i:integer):integer;

4begit

5迁i=0thenfact:=1

6elsefact#i*fact(i-1)

7end;

8begin

9fori:=0to5dowriteIn(i,*1=和ct(i));

10epd.

的情况下,确定fact()的值时,必须首先求fact(i—1)的值,在图4.16上,用图形表示了这种计算过程。例如,当求fact(2)的值

捕获.JPG

时,需要利用fact(1)的值,求Fact(1)的值时,需要利用fact(0)的值.对于这种情况,只要求出fact(0)的值,就能依次求出fact(1),fact(2)的值。就像在fact中调fact那样,在子程序执行过程中,再次调其程序本身这种工作方式称作递推调程(recursivecall)过

程。虽然从语法上说,像下列程序这样的递推过程可以无限制地继续下去,但是每调一次程序(组合嵌套变深),由于引进了新的局部变量,而使得现行程序推迟执行。故在现有的存贮器容量的允许范围内,递推过程只能进行有限次

programexample(output);vari:integer;

procedurep;

begin

writeln(i);i:=i41

P

end;begin

i:=0;

pend.

PCOM中子程序的调出为了在PCOM中执行含有递推过程的子程序的调出,将存贮器作如下分配。如图4.7所示,存贮器大多数区分为下列三个部分:(i)指令和常数,转移表的划分区域,(ii)调出子程序的参数,变量占据的区域,(iii)堆栈区域。(i),(ii),(ii)三个区域分别主要相当于(i)以const·开始的常数定义部分,和以begin,end包围的陈述语句,(ii)以var开始的变量描述部分,和procedure与function的变量部分,及function的返回值,(iii)进行四则运算等的时候,必要的暂时存贮区域,以及调出子程序时,返回原地址的存贮区域.在本书中,假想的PCOM采用的PASCAL语言中,为了简单化,设不能用new实现动态变量的生成。如果需要动态变量,则必须考虑被称作堆域(heap)的存贮区。

若子程序被调出,则PCOM将bp的值+1存人tp中,在执行这个子程序所必须的存贮器区域内,必须确保bp(帧栈底指针)值的增值区域(称为帧)。这样,当然也确保了递推过程的正常工作。因此,在求fact(2)时,在存贮器上需要存放与fact(2),faet(1),fact(0)对应的三献信息。

静态连接与动态连接在这一帧结构中,分配有静态连接(staticlink)、动态连接(dynamiclink)、自变量、局部变量。调出过程采用从tp指示地址开始的相对地址(即表示离开tp指示的地址的远近程度),从而可以对帧中每一条地址进行访问.例如,在下列程序中,要调出过程P时,采用了图4.17所示的帧结构,使用从tp指示的地址开始的相对位置(情况2),便可以访问局部变量

Pxogramexampleprocedarep;

yaririntegerbegin

i=1end;

beginP

ead.

捕获.JPG

帧结构中的动态连接是为了存贮新的tp值,这样,当子程序结束并调出bp的值时,就能够保证返回到改变了的子程序开始时的tp值。这就是说,当子程序被调出后,新的tp中装进原tp的值+1,而新的bp中则装进新的tp的值+(必要的存贮器数一1)。在动态连接中,装人原tp的值,若子程序结束,则bp中装人新的tp的值—1,tp中则装进动态连接的值。如果使用动态连接,则在描述局部变量的程序块中,是不会产生对这个局部变量的访问限制的。

我们来考虑下面的例子。

 

programexample;varb:integer

procedurepl;

procedurep2;begin

ifb<=Ithenbeginb:=b+l;

p2

eudend;

begin

b:=0;p2

end;begin

plend.

 

在这个程序中,因为p2被调出2次(递推的)时的帧结构图如图4.18所示,所以在访问变量b时,需要提供更多的信息。因此,能够对变量b进行访问的那种静态连接位于帧结构中。图4.19中那种静态连接的指示地址是较执行中的子程序更外一层的子程序帧结构的起点。(所调子程序的级,就是用来描述子程序的程序块

捕获.JPG

的级。)总之,动态连接表示的是子程序之间,在执行时的嵌套关系。与此对应,静态连接则表示源程序中的嵌套关系。在上面列举的程序中,对于过程p2帧结构的静态连接,指向对于pl帧结构的起点。对于pl而言,则是指向关于programexample的帧结构起点。因此在过程p2中,当访问变量i时,倒回静态连接寻找帧结构开头的次数,只能有子程序级差那么多次(这里等于2次)。将到达变量D的相对地址2,加到这个开头地址,计算变量b的地址,就可以实现访问变量i了在程序的执行中,确定静态连接的值时,需要知道正在调出方

捕获.JPG

面的子程序级数laing,与已被调出方面子程序级数1aed之差。设level=Iatliag—1e₁led,则被调出方面的子程序静态连接值,就等于从调出一方的帧结构开始,将静态连接倒回(1calling-lcaHied-+1)一(level+1)之后,达到的程序前面的地址,例如对于图4.20上的过程t,当调出q时,从x的静态连接开始,倒回(i+3)一(i+1)+1==3次而达到的程序前面的地址,就构成了过程中的帧结构先头地址。

pushb和popb具有下列leveI和addr两个值。从当前的帧开始,将静态连接倒回level次,可得到一个前面的地址,设此地址与addr的和为k,pushb将k地址的数据存人堆栈,popb从堆栈将数据转移到k地址。

捕获.JPG

例4.5在图4.21中,设执行pushb2,2,则静态连接从现在的tp指示的帧返回2次,然后将地址加2,即得到欲求的地址.将这个地址中的数据41(H)存入堆栈。对于popb2,3,可以用同样的方法计算地址,然后从堆栈将数据转移到该地址。

cuplevel,addr是从现在的帧的静态连接开始,返回(level+1)

次而达到前面的地址,然后将该地址存入地址bp+1(静态连接),并且将Lp的值存人地址bp+2(动态连接)。此外,pc的值被压入堆栈(退出在前),addr的值被存入pc,并且跳转到addr.地址。

endIcvar是一个限于对lcvar确保局部变量域的命令,它使新的.tp值与原bp值加1,新的bp值为新的tp值加lcvar再加1。(一般来说,procedure和function的变量均被拷贝入局部变量区内,而且变量和function的值域也被附带拷贝入局部变量区内.)

ret利用动态连接使tp和bp返回到子程序被调出以前的状态,并将压入堆栈内的数据(退出在前)存入pc内,从而恢复到原来的程序。

如果使用这个命令,则能够容易地调出子程序和进行局部变量存取,例如,当在下列程序中调出过程P时,只要生成下列中右边所列指令就行了.


prograntexample;procedurep;

begin

 

end;begin

 

p

 

end.


 

P-e0

ent0

 

ret

 

cup-1,p-e₀


 

执行上述指令时,将完成图4.22所示的过程。

(7)reti(op=F(H)

这个命令可根据子程序进行中断处理。当im—1(允许中断)时,它是一个恢复被中断的原程序命令。正如在4.1节中叙述的那样,中断要求一旦出现,程序的控制便转移到(地址1)一进人(眺转表)的地址,这时的情形虽然与调出子程序的情形非常相似,但在下列方面是有区别的:

(i)·子程序的调出,是在程序规定的地方发生的,中断发生在何处事先不知道。

(ii)利用静态连接的变最存取,是没有意义的。

(iii)imm0(不允许中断)状态时,跳转到中断处理子程序。

捕获.JPG

捕获.JPG

中断处理以用ent命令确保局部变量区为出发点。当中断处理结束时,执行reti命令,恢复到原来的程序,ret与reti的区别是,ret对应于im(中断屏蔽)的值不改变,而reti则是使im为1(允许中断)时的返回点。图4.23表示了这种情况。

(8)eni(op=10(H)),dsi(op=1l(n))

eni是使im变成1(允许中断)的命令,dsi是使im变成0(不允许中断)的命令。正如4.1节讲过的那样,根据复位信号,使im=0(不允许中断),并从地址0中的值所对应的地址开始执行程序。通常这个地址就是程序的人口。程序在对变量和IO设备进行了初始化以后,必须变成为已被接受中断的状态。这时,如果执行eni,则im=1,另外,在程序中尚存在有不希望加中断的部分。在这部分的前面,要执行dsi命令,而在这部分的后面,则要执行eni命令。

(9)ior(op=12(H))addr,iow(op一13(n)addr在PCOM中,存在有ior和iow这种指令,它们是用来访问存贮器地址和具有重复地址的外围设备的。正如4.1节讲过的那样,在PCOM的信号线上有mem/io信号,当访问存贮器时(pusha,popa,…),mem/io=1,当访问I0设备时(ior,iow),mem/io-0.总之,ior和iow将addr的值载入地址总线,此时mem/io=0,且as-1,如果将这些信号经过图4.3中那种译码器译码,则可以对IO设备进行访问。


随便看看