易码技术论坛

 找回密码
 加入易码
搜索
查看: 308760|回复: 10

[问题]RTI是什么??????

[复制链接]
发表于 2005-5-18 23:31:00 | 显示全部楼层
ReTurn from Interrupt
从中断服务程序返回.
有关RTI的一个用法,请参见徐哥网站上的一个帖子:
地址 http://xu.b0ne.com/bbs/viewthread.php?fpage=1&tid=240
精华帖,要注册才能看[em01]
发表于 2005-5-19 10:17:00 | 显示全部楼层
RTI可以活用。也就是说 可以不是“从Interrupt返回”。

RTI与RTS的区别在于:

RTS是返回到当前栈指针所指的地址+1。

而RTI则返回到当前栈指针所指的地址。

举个例子来说:

3000 JSR $8A00   20 00 8A

3003 RTS         60

8A00 PHP

8A01 RTI         40

注意这段程序的执行:

先跳转到$8A00,执行到RTI,则返回$3002,注意,返回后执行的不是3003 RTS,而是3002 8A(TXA)。


[此贴子已经被作者于2005-5-19 17:19:18编辑过]

 楼主| 发表于 2005-5-19 11:32:00 | 显示全部楼层
哦这样啊
RTI一般在什么场合上可以使用?
发表于 2005-5-19 16:52:00 | 显示全部楼层
Lendy的程序是有错误的,执行时不能达到预期效果.
原因如下:
RTI 在返回时相当于做了以下工作:
PLP
POP->PC_LOW
POP->PC_HIGH
JMP (PC)
也就是说,在返回之前还有个PLP的动作.
所以,Lendy的程序在运行时会把8A先弹给P,然后才会找返回地址.
如果在 8A00 处改成下面的,就没事了:
8A00: PHP
8A01: RTI
下面我也举个例子:
2000:JSR $2900   
2003:RTS                  (2002:AND #$60)
2004:RTS                  (2004:RTS)
第一种情况,使用RTS:
2900DA #$FF
2902:RTS
执行后 (A)=FF
第二种情况,使用RTI:
2900DA #$FF
2902HP
2903:RTI
执行后 (A)=60
发表于 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编辑过]

发表于 2005-5-19 17:09:00 | 显示全部楼层
抱歉。为了跟laugj讲明RTI与RTS在返回操作上的区别,而忽略了一些细节。。
发表于 2005-5-19 17:22:00 | 显示全部楼层
呵呵,我也搞错了,应该是先弹出02,而不是8A.
 楼主| 发表于 2005-5-19 22:48:00 | 显示全部楼层
原来如此
Lava解释器中
有将数据直接poke到代码所在内存中来跳转
类似:
4000:ASL
4001:TAX
4002DA $2000,X
4005:STA $400F
4008DA $2001,X
400B:STA $4010
400E:JMP $0000
如果换成
PHP
LDA $2001,X
PHA
LDA $2000,X
PHA
RTI
也可以吧,难道区别只是省了几个字节?
发表于 2005-5-20 07:53:00 | 显示全部楼层
不能说是"区别",使用RTI作为跳转方法,仅仅是RTI的一个巧妙利用而已,这并非是RTI的原本设计目标.
它们的区别嘛,自己一用便知,眼看也能看出,程序变得简单,保护变量少了.
发表于 2005-5-20 00:00:00 | 显示全部楼层
以下是引用laugj在2005-5-19 22:48:35的发言:
如果换成
PHP
LDA $2001,X
PHA
LDA $2000,X
PHA
RTI
也可以吧,难道区别只是省了几个字节?

不对.注意是先压地址,后压标志寄存器.
 楼主| 发表于 2005-5-18 22:33:15 | 显示全部楼层 |阅读模式
如题啊

RTI这指令有什么用?
您需要登录后才可以回帖 登录 | 加入易码

本版积分规则

Archiver|手机版|小黑屋|EMAX Studio

GMT+8, 2024-4-19 14:13 , Processed in 0.011001 second(s), 19 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表