2023.4.21
前へ
次へ
ホームページトップへ戻る


PICBASICコンパイラ

〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
まるでインタプリタ。でもコンパイラです。超カンタン超シンプルです。
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜

[第13回]



●LATレジスタ

前回はPRINT文のプログラムの説明のなかでI/Oポートの出力を確認する方法として出力に設定したIOポートから出力値を読むことができることについて書きました。
しかしそれに続けて下記のように書きました。

PORTCはI/Oポートですから本来はPICの端子の外にLEDなどを接続して出力を確認すべきなのですがこのように出力に指定したPORTを読むことでも出力値を確認することができます。
しかしこの方法は時として問題が発生する可能性があります。

今回はその問題について書くことにします。
下は前回と同じようなプログラムですが今回はPORTCだけに値を出力してそのあとPRINT文でPORTCの値を表示させるプログラムです。

/RUNで実行すると55が表示されるはずのところ00が表示されました。
問題発生です。
なんじゃこりゃ。
念のために/RDコマンドでPORTCの値を確認してみますとちゃんと55になっています。
夏にはまだ早いのですけれどまるで怪奇現象です。

実はこれがI/Oポートの問題点なのです。
初期のPIC(PIC16など)ではこの問題のためにI/Oポートに直接ビットセット、リセット命令を実行すると正しい結果が得られないことがありました。
そのためI/Oポートに対してビット命令を使う場合には直接I/Oポートに対してビット命令を使うのではなくてワークとして別に用意したレジスタに対してビット命令を実行してからそのレジスタの値をI/Oポートに出力する、という作法が必要でした。
この問題は”READ MODIFY WRITE問題”として知られています。
この問題の解決法としてPIC18などではI/OポートにLATレジスタが追加されました。
I/Oポートに出力した値を読む(確認する)にはPORTXを読むのではなくてLATXを読むようにすることでこの問題を回避できます。

上のプログラムのPORTCをLATCに変更してプログラムを実行しました。

今度は正しく実行されました。

念のためにもう一度さきほどのPORTCのプログラムをLOADして実行してみますと。

55を出力したはずなのにLATCに出力した値が読み出されました。
それではということで/RDコマンドで確認してみますとちゃんと55が読み出されます。
一体どうなっているの?
ということなのですがその理由はPICのDATA SHEETを読むとわかります。

下はPIC18F13K/14K50のDATA SHEETのI/O PORTの説明のところです。

[出典]Microchip Technology Inc. PIC18F13K50/14K50 Data Sheet

図の下部にRD PORTがあります。
どこの値をREADしているかというと図の右上のI/O PORT端子のところを入力しています。
一応出力端子の状態を読んでいるので問題はない、はずなのですが。
その一方で図の左上を見るとRD LATと書かれています。
こちらは出力ラッチの出力をIC内部で直接読んでいます。
RD PORTの場合、外部回路に接続されている端子の状態を読むためにどうしてもその端子の外部のラインの状態に影響されてしまいます。
I/Oポートの出力を0から1に(または1から0に)変化させてもたとえば外部ラインの浮遊容量などの影響で立ち上がりや立ち下がりが短い時間ですがわずかに遅れることが出てきます。
マシン語のプログラムは非常に高速なのでその遅れの影響が無視できません。
RD LATは出力ラッチの出力を直接読むためにそのような外部回路の影響を受けません。
出力ポートの値を読む場合でも出力した直後ではなくて少し間を空けてから読めばこの問題は回避されます。

下は出力と入力の間にFOR NEXT文を実行して間にわずかな時間を置いて実行した例です。

わずかな時間を置くことで正しい値が読み出せるようになりました。

LATレジスタとPORTレジスタは別々のものではなくて同一の回路上にありますから、PORTCに出力してPORTCから読む、LATCに出力してLATCから読む、というように区別して考える必要はありません。
PORTCに出力してLATCを読んでも全く問題はありません。
下はそのようにしたプログラム例です。


さて。
毎回のように書いていることですが。
上記の一連の作業ではプログラムをロード/セーブしたり一部を変更したりという作業を行なっていますがいずれも面倒な手続きなどを必要としないでいとも簡単に行なえていることがご理解いただけるかと思います。
BASICプログラムの記述そのものも極めて平易ですしプログラムを部分的に書き換えたりプログラム行を追加したりするなどの作業もスクリーンエディタの機能で簡単に行なえます。
今までのコンパイラのイメージからは想像もできないほどではありませんでしょうか。
実際どう見てもまるでBASICインタプリタではないかとの印象をもたれるのではないかと思います。
でも。
間違いなくBASICコンパイラなのです。
下はひとつ上の画面のFOR NEXT文を追加したプログラムを/RUNコマンドで実行したときに生成されたアセンブラリストファイルです。

2000 000e     movlw D'0'
2002 946e     movwf TRISC
2004 120e     movlw 12
2006 826e     movwf PORTC
2008 000e     movlw D'0'
200A 306e     movwf a
200C 0a0e     movlw D'10'
200E 1e6e     movwf to
2010 010e     movlw D'1'
2012 1f6e     movwf step
2014 18ec     call 30
2016 00f0 
2018      _2018
2018 1f50     movf step,w
201A 3026     addwf a
201C 3050     movf a,w
201E 1e5c     subwf to,w
2020 02e3     bnc +4
2022 0cef     goto _2018
2024 10f0 
2026 1d04     decf for_ad
2028 8250     movf PORTC,w
202A 14ec     call 28
202C 00f0 
202E 0a0e     movlw 0a
2030 16ec     call 2c
2032 00f0 

FOR〜NEXT文も含めてPICのマシン語コードにしっかり翻訳されています。
PICBASICコンパイラのFOR NEXTについては当初は作るのをやめようと思っていました。
今までのインタプリタでの経験からするとFOR NEXTはスタックを沢山使うためにPICでそれをするとすぐにスタックを使い切ってしまうと思ったからです。
ちなみにPIC18Fのスタックは16ビット×31しかありません。
FOR NEXTの代わりはNEXTの位置にIF文を置くことで代用ができます。
しかしせっかく作り始めたPICBASICコンパイラなのにFOR NEXTがないというのもみっともない話です。
なんとかコンパクトに作れないかと工夫した結果、なんとかできてしまいました。
なせばなる。
であります。

PICBASICコンパイラ[第13回]
2023.4.21upload

前へ
次へ
ホームページトップへ戻る