ケースジャンプの怪

 

addwf

PCL,self

retlw

'D'

retlw

'E'

retlw

'M'

retlw

'T'

PICでケースジャンプをするにはプログラムカウンタに直接加算命令で実現します。 テーブルデータを参照したい時は左の様に書きます。 このルーチンをcallで呼ぶ時Wレジスタにテーブル番号を入れて呼びます。 そうするとこのサブルーチンはその番号に対応したASCIIコードをWレジスタにセットしてリターンします。 固定文字列等をインプリメントする時の定型です。

addwf

PCL,self

goto

d_com

goto

e_com

goto

m_com

goto

t_com

BASICのON-GOTOの様にしたい時は、左のようにGOTOのテーブルにします。 PICの命令が1ワードで出来ているからできる荒技のようにも感じられます。

ADDWF PCL,self

解説書などにも良く見かけますが私は不思議?なことに気が付きました。 プログラムの記述は当然(左)なのですが、

私が今回使っているのは16F84ですからPCは14ビットです。 このPCLに対しての加算命令は8ビット(構成上加算レジスタが8ビットなので)のはずです。 当初あまり気にせず使用していましたがあるとき突然プログラムが暴走しはじめたので不思議に思いシュミレータで調べてみると加算結果が8ビットをオーバーフローしていました。 あれあれこれはPC上位にキャリーアップしない手抜きのCPUだな! と勝手に思い込みこの関連の命令はゼロページ(先頭の256バイトエリア)に配置するようにして問題を回避していました。

 ところがあるひシュミレータでデバッグしているとPCHにはPCLATHがロードされることに気が付きました。 マニュアルによるとPCLに対してデータをロードする時、(CALL,GOTOも含む)PCHにはPCLATHがロードされる仕様になっています。 (命令によりロードされるビットサイズが違う詳しくはマニュアル参照) これで事前にPCLATHにアドレス上位を書いておけばべつにジャンプテーブルをゼロページに置かなければならないという必要がなくなるな、と思った後おかしなことに気が付きました。 逆にPCLATHにPCHをロードする命令が無いのです。 この命令が無いならPCLATHをジャンプテーブルのロケート位置にあわせる方法がありません 唯一の方法は一度アセンブルしてアドレスを確認して、再度ソースを手直しする?ですか。 この方法だとプログラムを追加するたびに確認が必要になります。 それでは何のためにPCLATHがあるのでしょう?...

誰か教えて下さい 私には分かりません!.......

ご親切な方からアドバイスが有りました。

●PCLATHに、PCHをロードする方法ですが、下記でokです。
-----------------------------------------------------------------------
addwf PCL,W ;PCLATU,PCLATH コピー
-----------------------------------------------------------------------
●ただし、addwf PCL,Wが入っている所の、PCU,PCHがコピーされますので、テーブルデータが、PCHの変化する所(境界)に有ると、異常になります。これを、回避するには、次の方法が考えられます。

  • A.PCHの変化する所に無いことを、アセンブルしてアドレスを確認して、再度ソースを手直しする。
  • B.PCHの変化する所に、テーブルデータが入らないように、次の様PCLATU,PCLATH コピーしている前に、次のorgを設定する。
    ---------------------------------------------------------------
    org HIGH $ * 100h + 100h
    ---------------------------------------------------------------
    • C.addwf PCL,Fを、行った時の、必要な、PCH を予め計算しておき、PCLATHを設定しておく。(ご注意:私の使っている、PIC18用の計算Jump対応プログラム (★部分)です。16F84には、そのままでは、使えません。)
      ---------------------------------------------------------------
      ◎ movlw 02h ;例..プログラムは、RNO2DVへ、jmpします。
      rlncf nowcom,F ;x2
      rlncf nowcom,W ;x4...goto...
      ★ movlw 8 ;* オフセット分
      ★ addwf wjmp_temp,W
      ; .....................
      ★ addwf PCL,W ;PCLATU,PCLATH コピー
      ★ movlw 0 ;**
      ★ addwfc PCLATH,F ;**

      ★ movf wjmp_temp,W ;**
      addwf PCL,F ;**

      goto exec ;00
      goto RNO1DV ;01
      goto RNO2DV ;02
      goto RNO3DV ;03
      --------------------------------------------------------------

    特徴

    • A.は確認が面倒だし、前にプログラムを追加・削除したときは、境界が変化し
       その度の確認では、とても使えません。
    • B.は境界が変化する事は有りませんが、プログラム・エリアに”無駄”が生じます。  また、テーブル量も、少し少なくなります。
    • C.は、最善?の方法です。
       プログラム・エリアの任意の場所に、置いても構いませんし、テーブルデータも、 255個まで使えます。

    な〜るほど! たしかに... 参考になりました。 ご協力ありがとうございました。