- 注册时间
- 2004-9-4
- 最后登录
- 1970-1-1
|
发表于 2005-5-19 16:55:00
|
显示全部楼层
===========================================================
嫌间接寻址麻烦?试试用这种方法!
——深入浅出地剖析指令RTI的使用及技巧
未来的程序员们你们好!我深知编程的劳累,大家辛苦啦!
在平时编程中,我们肯定都遇到过这样的情况:程序运行到某一个地方,要根据计算结果或用户的反应情况转到不同的分支去。这时候我们一般会考虑使用查表法。用这种方法的大体形式一般是这样的:
LDA Value // 此处的Value是计算值或是用户响应值.
LDX #$00
Compare_Value: CMP Value_List,X
BEQ Found
INX
CPX #Count // 此处的Count是分支的个数.
BCC Compare_Value // 找下一个.
BCS Illegal_Value // 无此情况.
Found: TXA
ASL
TAX
LDA Addr_List,X // 取得要转向的地址低字节
STA $80
LDA Addr_List+1,X // 取得要转向的地址高字节
STA $81
JMP ($0080)
这个程序固然是很好很容易理解的,但它有一个缺点,那就是它要用到($80)和($81)两个地址.假如我们的这两个地址还有别的数据要用的话,就必须在程序前面使用堆栈保护这两个地址的内容,到了每一处分支的地方还得弹栈恢复.假如分支很多的话,就很麻烦.另一种解决方法是换个地址,换个未被其它数据占用的地址.可是一旦程序长了,恐怕连自己都不知道哪个地址没被占用了
.
一次我偶然记起PC530的中断服务程序中有段很特别的转向控制程序,它的原形是这样的:
LDA #$E6
PHA
LDA #$98
PHA
STX $D1
LDA #$00
PHA
LDA $D3
LDX $D5
RTI
(以上程序摘自PC530地址$E1F3处开始)
这段程序的主要功能是:将($D3)处的值给A,给标志寄存器赋值$00,然后控制程序转向$E698处继续执行.
这段程序使用了一个很特殊的指令——RTI.下面我们来分析一下RTI指令的工作原理.
在了解RTI之前,我们首先要知道INT中断的处理方式。也就是中断指令的响应过程。
6502处理器在遇到中断指令时,会把当前的程序计数器(PC)+2高低字节分别压入堆栈,再将标志寄存器的值压入,然后程序转向$FFFE向量处执行.比如有下面一段程序:
……
……
2000- LDA #$00
2002- BRK
2003- .DB $15,$8A
2005- LDA #$20
……
……
这段程序在2002处是怎么执行的呢?
在$2002执行之前,6502的各个寄存器的值如下:
(A)=$00
(PC)=$2003
执行$2002时,6502处理器会先将(PC)+2的值压入堆栈.也就是$2005.注意,高字节先进,低字节后进.先压入$20,再压入$05.然后,会将标志寄存器P的值压入堆栈.这段程序相当于执行如下过程:
……
……
2000- LDA #$00
2002- PUSH #$20
PUSH #$05
PHP
JMP ($FFFE)
2003- .DB $15,$8A
2005- LDA #$20
……
……
下面我们再讲一下RTI要做的工作。RTI是“ReTurn from Int”即“从中断中返回”的意思。6502在执行到RTI指令的时候,会做以下工作:
先从堆栈中弹出一个数据,送入标志寄存器P;然后再弹出两个数据,依次送给PC的低字节和高字节;最后转向PC所指向的地方继续运行。
我们还是看这个例子吧:
LDA #$E6
PHA
LDA #$98
PHA
STX $D1
LDA #$00
PHA
LDA $D3
LDX $D5
RTI
(以上程序摘自PC530地址$E1F3处开始)
它在RTI处执行的程序相当于做了如下工作:
PLP
POP->PC_LOW
POP->PC_HIGH
JMP (PC)
看到了吧,我们可以用PC作为间接寻址的操作数。方法就是采用RTI指令。首先模拟BRK(INT)指令将必要的数据压入堆栈,然后使用RTI指令来让6502处理器自己处理并转向。
这有什么用呢?我们来看一开始我们讲到的程序:
LDA Value
LDX #$00
Compare_Value: CMP Value_List,X
BEQ Found
INX
CPX #Count
BCC Compare_Value
BCS Illegal_Value
Found: TXA
ASL
TAX
LDA Addr_List,X
STA $80
LDA Addr_List+1,X
STA $81
JMP ($0080)
下面我们采用RTI的方法来实现,看看是什么样子的:
LDA Value
LDX #$00
Compare_Value: CMP Value_List,X
BEQ Found
INX
CPX #Count
BCC Compare_Value
BCS Illegal_Value
Found: TXA
ASL
TAX
LDA Addr_List+1,X
PHA
LDA Addr_List,X
PHA
PHP
RTI
可以看出,在这个程序里,我们使用了两个PHA和一个PHP来模拟出了6502处理器遇到BRK指令后所做的各项工作。
感觉怎么样?是不是要比间接寻址的方法省了很多字节很多要考虑的东西?对了,它不用保护特定的地址。
细心的朋友可能注意到一点,就是取地址的指令,原方法是先取低字节,这种方法则要先取高字节。这是使用时需要注意的。
好了,关于这个RTI指令和它在程序中的巧妙用法,到这里我已经讲完啦,以后写程序的时候再用到这种分支程序的时候就试试吧,应该比原来的方法节省不少脑细胞哦!就到这里,讲了这么多,茶都凉了。
(本文由 SAILOR-HB 首发于文曲飞扬论坛——文曲星编程俱乐部的基地)
===========================================================
[此贴子已经被作者于2005-5-20 7:55:54编辑过]
|
|