MPASM Technic – スタック

PIC18Fでは(PIC12やPIC16など比べ)プログラムによるスタック操作が追加されています。
サブルーチン呼び出しの際にPCがスタックにPUSHされ、ReturnでPOPされます。

これまでPICではプログラムから利用できるスタックがありませんでした。
PIC18FではニーモニックにPUSHとPOPが加わりました。

他のCPUと比べ、スタックの使い方には注意が必要です。
スタックメモリは、プログラムメモリ空間やFAST(ワーク)メモリ空間から分離されており、内容を直接自由にアクセスはできません。

リセット後は、スタックポインタは0(最先位置ポインタ)ですが、ここにはスタックメモリがありません。
PUSHを実行するとスタックポインタが+1され、次にPC+2がスタックに追加されます。
これは、PUSHは1ワード(2バイト)命令なので、戻りの際のアドレスがスタックされます。
PUSHの場合、スタックに入る値はPOPで捨てられますので、スタックをReturnに使用するテクニック以外ではあまり意味を成しません。

また、スタックメモリは別空間にあるため、TOSレジスタ(PC幅と同じく21bit)を通して現在のスタックポインタ位置の1レベルのみを部分の的にアクセスできます。
Push命令の実行直後は、結果として、呼出Push命令のプログラムアドレスに+2(PC+2)した21bitアドレス値がTOSレジスタに現れます。

POP命令でスタックポインタは-1されます。
POPにより、TOSレジスタが指す内容がPUSH前の状態に戻ります。

理解しやすいように、マニュアルの補足をします。
TOSレジスタは、スタックポインタと連動した、スタックメモリの読み書きウィンドです。
スタックポインタの指す位置は、一般的なCPUのように次に使用する空間を指しているのではなく、呼び出したルーチンへの戻りアドレスがそのまま見えているので、この内容を変更するとルーチンから戻れなくなります。
pushを実行することで、スタックレベルが1つ上がり、TOSが指し示す値は、現在使用していないスタックメモリへの位置(内容)となります。

 

さて、ここからが重要です。

マニュアルを見ても特には書かれていませんが、CPUを設計された方の意図としては、たぶんPUSH・POP命令と、TOSを用いた21ビット(TOSL8bit、TOSH8bit、TOSU5bit)の退避型ワークの提供を目的としていると考えます。

サブルーチン等で最初にpushを実行し、最後にpopすることで、その間ではTOS(21bit)が外部ルーチンから保護された独立したワークとして利用できます。
←スタックは31レベルもあります。

割り込みやサブルーチンのワークとして、容量は限られますが利用できます。
特に多重での割り込み、サブルーチンでは必須であり、WSやステータス、FSR,BSRなど重要なレジスタの保存、ループカウンタなどいろいろ応用ができます。

マクロでの利用例を示します。←文中にTabが入れられないので、くっついています。

注意:インストラクションとしてmovffでは、TOSをdistinationとして転送できない。逆方向の転送は可

WREGとSTATUSを保存します。
割り込みで重要です。
pushws macro
push
movwf TOSL, ACCESS
movf  STATUS, W, ACCESS
movwf TOSH, ACCESS
endm

popws macro
movf TOSL, W, ACCESS  ; 注意:MOVF実行によりZ,Nフラグが変化する
movff TOSH, STATUS   ; ので、ステータスレジスタは、MOVFF命令により最後に戻す。
pop
endm

 

BSR(バンク選択レジスタ)の保存
割り込みなどで重要です。
pushbsr macro
push
movwf TOSL, ACCESS  ; Wregを経由して保存作業するため、先行してWREGを保存する
movf  BSR, W, ACCESS
movwf TOSH, ACCESS
movf  TOSL, W, ACCESS  ; Resume Wreg
endm

popbsr macro
movff TOSH, BSR
pop
endm

FSRnの保存
マクロ引数は値として処理されるが、マクロ中の#v(para)記述は、para部分がマクロ呼び出しのTrimされた文字列に置換される。
例えば、マクロへの引数が1の場合、FSR#v(nFsr)LはFSR1Lに置換される

pushfsr macro nFsr
push
movwf TOSL, ACCESS     ; WREG経由でFSRを保存するために、Wregを一時退避
movf  FSR#v(nFsr)L, W, ACCESS
movwf TOSH, ACCESS  ; TOSへのMOVFFは使用できない
movf  FSR#v(nFsr)H, W , ACCESS ; FSRxHは4bitレジスタ
movwf TOSU, ACCESS   ; TOSUは5bitレジスタ
movf  TOSL, W, ACCESS    ; Wreg復旧
endm

popfsr macro nFsr
movff TOSH, FSR#v(nFsr)L
movff TOSU, FSR#v(nFsr)H
pop
endm

 

※ TOSレジスタの実体はスタックメモリなので、データビット幅はPC(ProgramCounter)と同じ21bit幅です。PIC18Fで一度にアクセスできるデータ(レジスタ)幅は8ビットです。(もしくは1ビット)
TOSL,TOSHレジスタは8bitとして利用できますが、最上位TOSUレジスタは5bitしかありません。
また、TOSUの読み出すと上位3ビットは常に0となります。

[追記-2017-07-26]
サブルーチンを呼び出す際、TOSにパラメータを入れて渡すことはできません。
Call命令実行により、スタックがPushされるため、当然TOSレジスタが指す先が移動します。
TOSから取り出すと、戻りPCを挿しており引き渡し値ではありません。

スタック内に保存されたデータのアクセスについて、割り込みをとめてStackPointerを直接操作すれば、できなくはありませんが、PIC18はSP間接アドレッシングはできませんので、高級CPUのようにはうまくいきませんね。
このレベルの操作を行いたいのであれば、Extended Instruction Modeで動作させてワークを使ったほうがスマートですね。

カテゴリー: MPASM, PIC, PIC18F, PIC18F46K40, PIC18FxxK40 タグ: , , パーマリンク