2018年5月26日 星期六

組合語言Assembly $符號與跳轉指令的運用(以MCS-51為例)

在大部分的語言中如果有'$'符號大多是代表當前指令在program ROM中的起始位置
這是在ASEM-51編譯器手冊截下來的文字


組合語言中經常會用到跳轉指令  這時候就要想一個合理的lable名稱
但有些地方實在是不需要特別加一個lable上去  可是不加lable又沒辦法跳轉
這時候'$'符號就很好用
像是:AJMP    $
此時程式就會卡在這一行不斷執行

來看一個一個有意義點的例子:
(節錄自MCS@51 MICROCONTROLLERFAMILY USER’S MANUAL)
這是一個在中斷的應用
第一行:只要P3.2在0的狀態就會一直卡在那裡,否則往下執行
第一行:只要P3.2在1的狀態就會一直卡在那裡,否則往下執行
第三行:結束中斷副程式

如果需要做短時間且不重複的DELAY
DJNZ    Rn,$
這樣也不錯用

那如果$加上+-符號是可行的嗎?
答案是可以的,但要注意跳轉指令的字節數(Bytes)
以這個例子來說:(把沒意義的lable(L0、L1...)用$取代)
這是我當初懵懂無知的想法
(想直接看答案請直接往下滑到底)
編譯出來動作是錯的! 換成lable後又正常了
我瞬間滿臉疑惑
於是我打開編譯器產生的.hex檔:
我默默的關掉,打開另一個.lst檔
這是用lable方法的lst檔:
這是用$+2方法的lst檔:
最左邊(Line)是原始程式中的行,最右邊是原始程式的內容
Addr對應下來的是:原始程式中指令對應到的program ROM的位置
而Addr右邊的是編譯後的HEX

經查表後發現BD 是 CJNE    R5,#imm,rel
而BD後面的值是#imm的值   (CJNE    R5,#01H,rel)>>(BD 01 ??)
#imm後面的rel...
雖然這邊寫的是rel,但你往下翻完整的資料會看到


關於rel的解釋(節錄自Atmel 8051 Microcontrollers Hardware Manual):


簡單來說這裡要填入的是destination address(label、actual address)
然後編譯器會自動計算成相對偏移值(偏移值範圍 -128 ~ +127)

那再回去解讀剛才用lable方法產生的.lst檔案,可以發現都是
BD ?? 02
不管CJNE後面放的lable是甚麼對應到的rel都是02

那為什麼換成$+2後會變成FF(-1)呢?
再去翻翻資料
可以看到Operation其中一個是PC(Program Counter)=PC+3
因為該指令在program ROM中佔了3Bytes(可以解讀成三行),所以PC要+3才能執行下一道指令

問題就在這邊
假設CJNE在program ROM中的位置是0000H~0002H
CJNE    Rn,#data,$+2
這邊的$+2會變成 (0000H+2 = 0002H)
本來PC+3=0003H;現在為了偏移到0002H,程式編譯出來的相對偏移值就會變成-1

所以基本上+2這個想法沒問題,問題在指令的字節數
在考慮字節數後我們整理成表格如下
如果我們要讓CJNE觸發後跳轉到下一個CJNE應該要使用 $+5


所以正確的方法應該是
$+(跳轉指令字節數-1)+(後面指令的字節數)+1 
$+(跳轉指令字節數)+(後面指令的字節數)

$+3+2 = $+5


Assembly、$ Symbol、Jump Instructions、$ Symbol Jump
$+1、$+2、$+3、$+4、$+5、$+6、Conditional Jumps

沒有留言:

張貼留言