積極的にユーザースタックを作成する方法を紹介する。
これは、FSR2(FSR0,1でも良いがFSR2を推奨)を用いたユーザースタックである。
ここで、ユーザースタックを構成する場合に重要なこととして極力メモリを食わずに高速であること。またスタック操作でCPUフラグが変化しないことである。
以前TOSを用いたスタック的な利用方法を紹介したが、TOSを用いた場合、ワークメモリとして利用するTOSL,TOSH,TOSU(5bit)を1word 1clkでスタック保存する。
今回紹介するテクニックでは、TOS、PCLを除く、すべてのレジスタを2word 2clkでPush,Popする。また、Pushしたレジスタ値はどのレジスタにもPopできる。
動作原理
FSR2をスタックポインタとしてリセット後にRAMの末尾(別に末尾でなくとも良いが)を設定する。以降FSR2はスタック操作以外で利用してはいけない。
Pushする際は、POSTDEC2レジスタ経由でメモリを保存する。
このレジスタは、FSR2で指し示すアドレスのメモリへのアクセスを行い、命令終了後FSR2レジスタをWORDデクリメントしてくれる。
Popする際は、PREINC2レジスタ経由でメモリを保存する。
このレジスタは、FSR2を1つWORDインクリメントした後、指し示すアドレスのメモリへのアクセスを行う。
この際にMOVFF命令を用いることで、BSRを用いずに全RAM空間を直接アクセスでき、またCPUフラグも変化しない。(movfはフラグが変化する。)
スタックの方向としては、RAM末尾→先頭方向となる。
このように設計したには、FSRレジスタの操作にPREDEC操作機構がないためである。
ユーザースタック操作を使用する場合、MACROで専用のコマンドを定義しておくと使いやすい。
pushu macro fAdrs
movff fAdrs, POSTDEC2
endm
popu macro fAdrs
movff PREINC2, fAdrs
endm
また、WREGなどは、あらかじめ引数を用いないマクロを作っておくと便利である。
; WREGの保存
pushuw macro
movwf POSTDEC2
endm
popuw macro
movff PREINC2, WREG ; movf はフラグが変化するので使用しない
endm
私の場合、その他にFSR0,FSR1,BSRや特定エリア(WORK)をMACROコマンド化することで便利にスタックを使用している。
最終的にはExtendedを用いたいところではあるが、最初からすべてExtended対応にする必要があるため、今回は断念。