[轉貼]指令RTI的使用及技巧

6502 組合語言,是哈電族裡使用的程式語言,也是目前設計 Bin 的唯一方法,有興趣的就進來吧
回覆文章
頭像
sppmg
一級會員
一級會員
文章: 260
註冊時間: 2004-01-10 12:41 PM
來自: 地球ㄉ台灣ㄉ台北
聯繫:

[轉貼]指令RTI的使用及技巧

文章 sppmg »

轉自http://wqx.4irc.com/bbs/viewthread.php?fpage=1&tid=240
===============================================

嫌間接尋址麻煩?試試用這種方法﹗
──深入淺出地剖析指令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 首發于文曲飛揚論壇──文曲星編程俱樂部的基地)
好久沒完6502了
也沒時間......
目前除了拼課業就是玩Linux(還說沒時間......)
回覆文章