51 單片機(jī)匯編語(yǔ)言:利用 RET 指令實(shí)現(xiàn)多路分支
有這樣一個(gè)問(wèn)題:
已知程序執(zhí)行前有 A = 02H,SP = 52H,(51H) = FFH,(52H) = FFH。
執(zhí)行下列程序:
? ? POP ? DPH
? ? POP ? DPL
? ? MOV ? DPTR, #4000H ?
? ? RL ? ?A
? ? MOV ? B, A
? ? MOVC ?A, @A + DPTR
? ? PUSH ?A
? ? MOV ? A, B
? ? INC ? A
? ? MOVC ?A, @A + DPTR
? ? PUSH ?A
? ? RET
? ? ORG ? 4000H
? ? DB ? ?10H, 80H, 30H, 50H, 30H, 50H
求程序執(zhí)行后:
A=( ?)H、SP=( ?)H、(51H) =( ?)H、(52H)=( ?)H、PC=( ? ?)H。
------------------------------
這個(gè)問(wèn)題,在百度知道出現(xiàn)過(guò)很多次,搜一下,就會(huì)出來(lái)幾十個(gè)鏈接。
但是回答正確的,確實(shí)不多。
有的提問(wèn)者,好像是說(shuō),這是什么學(xué)校教材上的習(xí)題。
在這個(gè)程序中,寫(xiě)錯(cuò)了兩條指令:
非法指令:PUSH ?A
應(yīng)該寫(xiě)成:PUSH ?ACC
做為教材來(lái)說(shuō),這可是一個(gè) BUG 啊,呵呵
這個(gè)程序,是利用 RET 指令來(lái)進(jìn)行多路分支。
程序中,有兩條查表指令:MOVC ?A, @A + DPTR,
當(dāng) A = 0 時(shí),將從 4000H 處,先后讀出 10H、80H;
當(dāng) A = 1 時(shí),將從 4000H 處,先后讀出 30H、50H;
當(dāng) A = 2 時(shí),將從 4000H 處,先后讀出 30H、50H。
本題目的條件已經(jīng)給出:A = 02H,那么就是讀出了 30H、50H。
讀出數(shù)據(jù)后,先后壓棧,再執(zhí)行 RET。
RET 指令,就是把堆棧中的兩個(gè)字節(jié),送到 PC。
那么,PC = 5030H,就是這么來(lái)的。
全部的空格,填寫(xiě)如下:
A=(50)H、SP=(50)H、(51H) =(30)H、(52H)=(50)H、PC=(5030)H。
------------------------------
本程序,是個(gè)子程序結(jié)構(gòu),應(yīng)該用 CALL 指令來(lái)調(diào)用。
在本程序開(kāi)始處,用 POP 指令,拋棄了 CALL 自動(dòng)保存的返回地址。
騰出了兩個(gè)字節(jié)的堆??臻g,又壓入兩字節(jié)數(shù)據(jù),然后,再返回。
RET 返回指令,就會(huì)用剛剛壓入兩字節(jié)數(shù)據(jù),當(dāng)做返回地址。
本程序,是屬于偷梁換柱,還是移花接木 ?
------------------------------
下面逐條解釋一下:
? ? POP ? DPH
? ? POP ? DPL ? ? ? ? ? ;彈出兩次,SP = SP - 2 = 50H
? ? MOV ? DPTR, #4000H ?
? ? RL ? ?A ? ? ? ? ? ? ;乘以2
? ? MOV ? B, A ? ? ? ? ?;B = 04H
? ? MOVC ?A, @A + DPTR ?;取出第4個(gè)字節(jié)30H
? ? PUSH ?ACC ? ? ? ? ? ;SP = SP + 1 = 51H, (51H)=30H
? ? MOV ? A, B
? ? INC ? A ? ? ? ? ? ? ;A = 05H
? ? MOVC ?A, @A + DPTR ?;取出第5個(gè)字節(jié)50H
? ? PUSH ?ACC ? ? ? ? ? ;SP = SP + 1 = 52H, (52H)=50H
? ? RET ? ? ? ? ? ? ? ? ;子程序返回指令
執(zhí)行 RET 指令時(shí),是從堆棧中彈出兩個(gè)字節(jié)到 PC 的高、低八位。
即:
(SP) → PCH,然后 SP - 1 → SP;
(SP) → PCL,然后 SP - 1 → SP。
即:
(52H) = 50H → PCH,SP = 51H
(51H) = 30H → PCL,SP = 50H
那么,PC = 5030H,就是這么來(lái)的。
------------------------------
進(jìn)行多路分支,還有簡(jiǎn)單一點(diǎn)的方法。
如,利用指令:JMP ?@A + DPTR,就可以。
那么,前面的程序,可以改為:
? ? MOV ? DPTR, #4000H ?
? ? RL ? ?A
? ? MOV ? B, A
? ? MOVC ?A, @A + DPTR?
? ? XCH ? A, B
? ? INC ? A
? ? MOVC ?A, @A + DPTR ;先后讀出兩字節(jié)
? ? MOV ? DPH, A ? ? ? ;把讀出數(shù)據(jù)送到 DPTR
? ? MOV ? DPL, B
? ? CLR ? A ? ? ? ? ? ?;A=0
? ? JMP ? @A + DPTR ? ?;以 DPTR 內(nèi)容為目的地,轉(zhuǎn)移
? ? ORG ? 4000H
? ? DB ? ?10H, 80H, 30H, 50H, 30H, 50H
程序這樣寫(xiě),就不涉及堆棧了,也就沒(méi)有前一個(gè)程序那么復(fù)雜的推導(dǎo)。
理解起來(lái),可以輕松些。
這個(gè)程序,沒(méi)有使用 RET 指令,那么,就不要用 CALL 來(lái)調(diào)用了。
要用 JMP 指令來(lái)應(yīng)用本程序。