义隆单片机课堂
EM78P447S单片机入门与实作系列讲座

🏠 首页 《无线电》杂志 2002年 🔗 第9期 🔗 第1065353216页 分类:电脑与单片机 🔗

三、工作寄存器体选寻址的处理方法

通过前面EM78P447S单片机指令系统的学习,我们可以发现,所有面向字节操作和面向位操作的指令,其指令代码中均包含一个6比特长的寄存器单元地址R。因为2的6次方等于64,所以R最多可以区分64个单元。但是,事实上EM78P447S内部的RAM配置了256个单元的地址空间,是64的4倍,地址编码长度需要8比特,从00H到FFH(即00000000B~11111111B)。如果想用6比特地址码(从00H到3FH=000000B~111111B)实现对256个单元的寻址,就必须对工作寄存器采取一种新的组织方法。这就是将长度为256的工作寄存器空间均匀划分为4等份,每一等份称作一个“体”,按地址从小到大的顺序分别记为“体0”、“体1”、“体2”和“体3”。

区分4个体需要2比特地址码(从00B到11B),我们不妨称该地址码为“体选码”。通常把体0~体3这4个体按横向顺序排列(见图4所示),每个体内含有64个单元的地址编码。当访问RAM中的某一个单元时,首先要确定包含该单元的体作为“当前体”(加电后单片机自动将“体0”默认为当前体),然后用包含在指令码中的6比特地址码R(即体内地址码),对指定单元进行定位。

图2
图2 🔍原图 (709×431)

在图4中,体1~体3内的阴影部分空间没有配置寄存器,这就使得对R0~R1F及R3F访问时,可以忽略体选码的内容。或者说,当对于阴影部分进行寻址时,将自动映射到体0的相应单元上。

体0内地址码为00H的IAR寄存器,其实是一个虚寄存器,它只有地址编码,而物理上并不存在这个寄存器单元。用它来与RSR寄存器配合,实现对RAM的“工作寄存器”空间进行间接寻址。当访问IAR时,实际上是在读写以RSR内容为地址的RAM工作寄存器内的数据。如图4所示。在EM78系列单片机中采用这种别具一格的设计手法,可以使指令系统得到极大地简化。

在图4中描述了两种寻址过程中工作寄存器地址的形成。对于直接寻址方式,体选码来自RAM选择寄存器RSR的最高2位,体内的单元地址直接来自指令码(低字段);对于间接寻址方式,体选码也来自RAM选择寄存器RSR的最高2位,但是体内的单元地址却来自RSR的低6位。对此也可以这样认为,一个单元的位置是由体选码和体内地址码两部分地址确定的。另外需要说明一点,对于特殊功能寄存器空间中的寄存器只能进行直接寻址,不能进行间接寻址。


[例3]
通常将“体0”作为当前体,开机后单片机默认的当前体也是“体0”。如果打算对“体3”中的一个名为VALUE的寄存器变量(设地址为25H的单元),进行写入操作,写入一个数据0FH,那以事先需要设定RSR寄存器中的体选码,事先还需要还原该体选码。程序段的编写如下:

RSR == 04H ;将符号名RSR定义为04H,因RAM选择寄存器地址为04H

RSR1 == 7 ;将体选码RSR1定义为7,因该比特在RSR寄存器中的位地址为7

RSR0 == 6 ;将体选码RSR0定义为6,因此比特在RSR寄存器中的位地址为6

VALUE == 25H ;将寄存器变量名VALUE定义为25H

BS RSR,RSR0 ;将RSR寄存器的BIT6置1

BS RSR,RSR1 ;将RSR寄存器的BIT7置1,以选择体3

MOV A,@0FH ;将0FH送入累加器A

MOV VALUE,A ;将A中的0FH转送到VALUE寄存器中

BC RSR,RSR0 ;将RSR寄存器的BIT6清零

BC RSR,RSR1 ;将RSR寄存器的BIT7清零,以恢复体0为当前体

四、程序跨页跳转和跨页调用的处理方法

由于EM78P447S单片机,片内配置的程序存储器ROM的容量为4K×13,因此,其地址编码长度为12位,212=4K。

EM78P447S的指令系统中,两条引起程序长距离跳转的指令JMP和CALL,所携带的地址码仅有10位,2的10次方等于1K,也就只能在1K(即为一个页面)的地址范围内跳转。但是对于程序存储器容量超出1K的情况(更严格地讲,是用户程序在存储器中分布的范围超出1K的情况),就可能遇到程序跨页跳转和跨页调用问题。

因此,就把4K的程序空间分为4页,每页1K,页面0、1、2和3的地址范围分别为000H~3FFH、400H~7FFH、800H~BFFH和C00H~FFFH。再把STA-TUS〈6~5〉位(即状态寄存器的PS1和PS0,复位时自动清零)作为页面选择位,不妨简称页选位,这样就可以在4K的地址范围内自由跳转了。

方法是当发生跨越页面的跳转时,事先预置STATUS〈6~5〉位,使其指向所希望的页面(0、1、2和3),见图5。在程序的执行过程中,当遇到JMP和CALL指令时,程序计数器的低10位,即PC〈9~0〉由指令码携带的10位地址装载,而PC〈11~10〉由STATUS〈6~5〉位自动装载,以选定4个ROM页面之一(见表2)。从而可以使程序的执行顺序发生跳转,并且可以在4个不同页面之间自由跨页跳转。

图1
图1 🔍原图 (532×185)
图4
图4 🔍原图 (393×185)

不单单是在执行JMP和CALL指令时,另外在执行其他改变程序计数器PC值的指令时,也将发生PS1和PS0被自动装载到PC的最高两位的情况(如图6所示)。

程序计数器PC是一个12位宽(记作A11~A0)的专门提供程序存储器地址的寄存器。可以将PC的12位看成3段:(1) A7~A0。低8位能够同普通寄存器一样可读可写;(2) A9~A8。两位却不能读出,也不能直接写入,只能维持不变或被间接清0;(3) A11~A10。两位却不能读出,也不能直接写入,只能用STATUS寄存器的PS1和PS0两位装载的方式来间接写入。

当执行JMP或CALL指令时,A9~A0低10位地址来自指令码(见图5);当执行以PC为目标(即目的地)的指令时(比如MOV R2,A;ADD R2,A;BCR2,6等),PC的低8位来自算术逻辑单元ALU,PC的A11~A10来自STATUS寄存器,A9~A8自动被清0(见图6)。这种情况引起的程序跳转,落脚点只能是每个页面的前1/4的空间之内(即前256个ROM单元上);当执行查表指令TAB时,会自动将累加器A中的内容叠加到PC上,并且PC的A9~A8保持不变(见图7)。

图3
图3 🔍原图 (532×206)

[例4]
假设在某一单片机的程序存储器中存放着这样一个程序,其主程序部分放置在页面0(从000H到3FFH)内,子程序部分放置在页面1(从400H到7FFH)内。主程序对子程序的调用是一个跨页调用。

STATUS == 03H ;将状态寄存器地址定义为03H

PS1 == 6 ;定义页选位PS1的位地址为6

PS0 == 5 ;定义页选位PS0的位地址为5

ORG OFFFH ;地址为FFFH的单元专门用作复位矢量

JMP MAIN ;存放一条到主程序的跳转指令

ORG 100H ;从页面0的100H单元开始存放主程序

MAIN BS STATUS,PS0;预置页选位,准备选择页面1

CALL SUB1 ;调用子程序,引起程序跳转

LOOP …… ;从子程序返回后执行的第一条指令

;——————————————

ORG 500H ;假设从页面1的500H单元开始存放

SUB1 MOV A,@00H ;子程序

……

RET ;返回到位于页面0的主程序的LOOP处

END ;源程序结束

从程序中可以看出,在子程序的返回指令RET之前不必理会页选位PS1和PS0,这是因为在发生跳转时,程序计数器PC内的12位地址码先被压入堆栈中保留,然后才用来自STATUS的页选位和来自CALL指令的10位地址码装载。在子程序执行完毕返回时,从堆栈顶部弹出PC的原值,从而可以使程序返回到原先的页面中。

实际上,并不是每次编程时都会遇到跨页跳转问题。只有当程序跨页存放,并且起跳点和落脚点分别处于不同的ROM页面时才会遇到。

大海创作室