忍者ブログ
ようこそ!JQ2RVNのブログです。 PICを使っていろいろな物を作ろうと画策中です。
[10] [11] [12] [13] [14] [15] [16] [17]
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

CCS Cコンパイラを使っている時、
条件文が、アセンブラに翻訳されるかを調べてみました。
さらに、どのように書けば最適であるかも調べました。

まず、以下のような処理を考えます。

UARTで8ビットのデータを送信するとき、
8ビット分は処理Aで、ストップビットを処理Bで行う。

通常ならば、while文を使うところですが、
タイマーの割り込みを使っているなどの理由で
if文にしないといけないということにしておきましょう。

順当に書けばこんな感じでしょうか?

i++;

if( i > 8 )
    処理B
else
    処理A

しかし、この場合if( i > 8 )の計算のために
引き算をしてキャリービットを検査するなど、
かなり面倒な条件処理になります。

 


 

逆にiを減算していったほうが、処理としてはスマートになります。
初期値としてi=8を与えておいて

i--;

if( i == 0 )
    処理B
else
    処理A

こうしておくと、
decf i,f
btfsc status , z
goto else
となって、2命令で条件分岐できそうと考えます。
が、しかし、そうはなってくれません。

どうやら、i==0と比較しようとすると、
8ビット幅でチェックしようとするみたいで、
結局XOR命令を使ってしまいます。
( A XOR B = 0 ならば A = B を使う)

 


 

このあたりを考慮すると、if文内はビット演算として書かないといけないようです。
つまり、比較演算子(==とか>とか<とか)を使わずに、
if( i ) のような書き方をすべきなのです。

さらに、デクリメント演算はif文の中に入れてしまう。
ただし、0の時の処理はif文直下(else内ではないという意味)に来るようにする。
つまり、if( ! --i )とします。

まとめると、

if( ! --i )
    処理B
else
    処理A

と書きます。

コンパイルされたアセンブラは以下のようになります。

  decfsz i,f
  goto else

  処理B
  goto end_if

else

  処理B

end_if

decfszは、
iから1ひいたものをiに入れ、その値が0なら次の命令を飛ばす
というものです。
1つの命令で、mov命令もsub命令も、条件判定もしてくれるので
高速でROMの節約にもなります。

 


 

論理を逆にして
if( --i )
    処理A
else
    処理B
としても良さそうですが、
コンパイラは処理A → 処理Bの順で翻訳するので(自動的に入れ替えてくれない)
余計な処理が入ります。

 


 

ポイントをまとめると

  • 回数の決まった処理では減算カウントをする
  • デクリメントの処理はif文のなかに
  • 0になった時の処理はifブロックに、0以外ではelseブロックに
  • 結果的に条件節は否定(!)になる。
  • アセンブラリストでdecfszに変換されているかチェックする。
というようになります。

 

この原則を守ると、可読性が失われる時もありますが、
処理の高速化やROMの節約にもなります。


コーディング時に考えるのは難しいので、
後でアセンブラリストを見て、考えるのでもいいと思います。

PR
今日はAX.25のSSIDについて書きます。

プロトコルの仕様書を読めばわかるのですが、英語なので・・・


AX.25において、送信元コールサイン、宛先コールサイン、デジコールサイン、
これらは7ビット構成でフォーマットも同じです。


最初の6バイトはコールサインが入っています。
ただし、ASCIIコードが左に1回シフトされています。
よって、基本的には最下位ビットは0になります。


つぎの1バイトにはSSIDが入っています。
ビットの構成は HRRSSSSF となります。

H ・・・ デジピート済みを表します。
RR ・・・ 予約
SSSS ・・・ SSID。これによりSSIDは0~15の値になります。
F ・・・ デジの最終地点を表します。



それぞれの解説していきます。

まず、SSSS。
受信の際にはSSIDバイトを1回右シフトして、0x0FのANDを取れば、
SSIDの数値を得ることができます。
逆に送信時には、SSIDを1回左シフトして、ORを取ります。


Fビット。
ここが1になっている場合、次のバイトはControl Fieldで、
さらに次はProtcolIDであるとわかります。

コールサイン部分を左にシフトするのは、実はこのためのようです。
つまり、最終ビットをみていって、1が出てきたら、アドレス類は終了だと判断できますから。
AX.25の場合、アドレスは7バイト固定なので、SSIDバイトをみればいいのですが、
昔の名残とか、そんなやつなんでしょうか??


最後にHビットです。
ここのフラグが1になっていれば、そのアドレスまではデジピートされていることがわかります。

デジピータは、先頭からスキャンしていき、このフラグが1になっているところを探します。
もし見つかったら、その次のバイトから7バイトが、
自局のコールサイン・エイリアス
に合致しているか調べます。
合致していたら、その部分をコールサイン置換するなりします。
そして、ひとつ前のアドレスのH=1をH=0に変更し、
自分のSSIDフィールドのHを1とします。

ちなみに、APRSなどのパケットでコールサインの後ろに'*'がついていることがありますが
これは、Hビットが1だった場合、コールサインの後に*をつけ、
人間の視覚上わかりやすくしています。


以上で、SSIDバイトの解析は終わりです。


忍者ブログ [PR]
カレンダー
12 2025/01 02
S M T W T F S
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
プロフィール
コールサイン:
JQ2RVN
性別:
男性
自己紹介:
PICの開発を勉強中です。
目標はPICTNCの高性能版を作ること。
まずは、本家を解析しています。
最新コメント
[04/23 Eolande]
[04/16 太田和巳(JF2UJG)]
[09/10 je7ifp]
[08/06 JQ2RVN]
[08/03 OVC]
最新トラックバック
バーコード
ブログ内検索
アクセス解析