SNSへはこちら

RXにある特殊な命令とアセンブリLチカ

最近はスタートアップルーチン手書きに嵌まっています。その時に見つけた RX の命令で「おっ!?」となったものがあったのでかる〜くご紹介します。

SSTR命令

C言語におけるスタートアップルーチンでは .bss セクションを全てゼロ初期化する必要があります。ルネサス社謹製のスタートアップルーチンではここをどう処理しているのかあと思ってみてみたら...

/* bss initialisation : zero out bss */

    mov    #00h,r2      /* load R2 reg with zero */
    mov    #_ebss, r3  /* store the end address of bss in R3 */
    mov    #_bss, r1     /* store the start address of bss in R1 */
    sub   r1,r3           /* size of bss section in R3 (R3=R3-R1) */
    sstr.b

こんな感じです。レジスタの順番が謎ですが、これはこの sstr 命令に起因しています。 _ebss_bss はおなじみリンカスクリプトで定義されているものです。以下のように。

    .bss : 
        {
            _bss = .;
            *(.bss)
            *(.bss.**)
            *(COMMON)
            *(B)
            *(B_1)
            *(B_2)
            _ebss = .;
            _end = .;
        } > RAM

以上を鑑みて、上のアセンブリコードは以下の処理をしているのだと推測が付きます。

  • r2 レジスタに 0 を入れている
  • r3 レジスタに .bss セクションの末尾アドレスを入れている
  • r1 レジスタに .bss セクションの開始アドレスを入れている

...とまあここまで来ると「memsetか??」と察しが付きますね。「RX ファミリ ユーザーズマニュアル ソフトウェア編」によると...

とまあドンピシャですね。しかも r3 を更新さえすれば、連続してストリングストア(memset)することが出来ます。

ふとここで気づくのが、「これって C言語の memset の引数順じゃね?」ということです。すなわち、第1引数に開始アドレス、第2引数に値、第3引数に末尾アドレスを渡しているということです。man ページによると

名前
memset - ある一定のバイトでメモリー領域を埋める。

書式
#include <string.h>

   void *memset(void *s, int c, size_t n);

説明
memset() は s で示されるメモリー領域の先頭から n バイトを c で埋める。

返り値
memset() は s へのポインターを返す。

とのことです。返り値の仕様は異なりますが、引数順はこのとおりですよね。では _memset の中身を見てみましょう。


...とまあまんまこれを使っています。アーキテクチャが C言語 に寄せてきた、とも考えられそうです。

ところでちょっと違う命令に memcpy とか言うのがありますよね。その部分も見ていて「ん?」ってなったのでご紹介。


ここに smovf という命令が使われています。もふもふみたいですね。こんな機能のようです。

これもまんまです。

名前
memcpy - メモリー領域をコピーする。

書式
#include <string.h>

   void *memcpy(void *dest, const void *src, size_t n);

説明
memcpy() はメモリー領域 src の先頭 n バイトを メモリー領域 dest にコピーする。コピー元の領域と コピー先の領域が重なってはならない。重なっている場合は
memmove(3) を使うこと。

返り値
memcpy() は dest へのポインターを返す。

というわけで以上、CISC だからこそできる、特殊命令の一部の紹介でした

アセンブリでLチカ

ARM でやったので、この次にいじっている時間が長いであろう RX でもやってみようとなったのでコードをぺたっと貼るだけで失礼します。まあ、RX ちゃんとも直接お話したいよね

CMT (コンペアマッチタイマ)ですが、やはりコンペアマッチ値レジスタの値が端数だと上手くカウントしてくれなかったり、色々癖があるようです(多分。それか日頃の行いが悪いから?)。ですがチカチカ出来たので良いということにします。

コメント

  1. forth83 より:

    RX220のCMTならPeripheral Driver Generator v2というツールを使うと比較的楽にタイマーの動作を確認しながらパラメータを決められるかもしれません。
    私はRX62NのMTUやRX210のRSPIを利用するにあたりこのツールを使って動作を把握しました。

    コード生成まで使うと巨大なライブラリ(Renesas Peripheral Driver Library)がリンクされるのでパラメータだけ参考にするといいかもしれません。

    e2studioやCS+のコード生成ツールにも似たような機能が入っているとは思うのだけれどそちらは調べてません。

    • shima-529 より:

      コメント有難うございます!
      PDGは視覚的にわかりやすいツールですよね。クロックの分周やタイマのPWM値等目で見てその挙動が分かるのはとても嬉しいです。多分STM32のCubeMX等でもこのようなわかりやすい表示はないと思います。

      実際にコードを生成してみましたが関数のトレースが億劫になってしまい進捗はありません。
      暇ができ次第、また気が向き次第調査していこうとは思います。ありがとうございました。

  2. 匿名 より:

    ご存じかもですが、Z80 LDIR で検索してみては?

    • shima-529 より:

      実はZ80、まだ未開拓なんです。古いトラ技を買ったりとやる気はあるんですが、まだ手が出せていません。
      この LDIR 命令、まさに memcpy() なんですね!勉強になりました。

      現状Z80はシミュレータ的なのをいじっただけなのですが、知りませんでした〜