2011年02月03日

AVR Toolchain

Tiny20/Tiny40 の記事を書いたときに AVR Toolchain というのが出てきて、なにこれ?状態だったのだが... 実は WinAVR の開発は終了して AVR Toolchain に引き継がれたらしい。いまさらながら知った。どおりで 新しい WinAVRが出ないはずだ。

正規の AVR Toolchain は、Atmel のサイトで レジストすれば AVRStudio 4 の addon として手に入る。

だが、AVRStudio 4 は使っていないし、WinAVR 相当だけが欲しい。 そして それを手にするのにレジストするなど論外。.. どうしたら良いのだろう?

とりあえず、レジストなしで入手できる、AVR Tools Beta Site に行ってみると、AVR32 Studio 2.7 (Windows 版と Linux 版がある) の zip がダウンロードできた。

    300MB 前後のサイズだが、それらしいものは、これしかない。

    中をみてみると (AVR32 ではなく) AVR の gcc (avr-gcc.exe )などがあった。どうも WinAVR 相当がまるごと入っているかんじで avr32-gcc.exe と avr-gcc.exe が ひとつの Tree に入っている。

    WinAVR 相当を抜き出して zip で固めると 85MB 程度になって、正規の AVR Toolchain と同じぐらいのサイズになる。さらに、avr32 関係と doc/info/man とか削ってみたら zip で 30MB 程度になった。

    これぐらいなら、インストールしても良いかなと思い、展開して PATH を通してみた。

    で、ビルドしてみると一応使える。gcc のバージョンは 4.4.3 。ビルドしたバイナリのサイズは WinAVR-20100110 より少し大きくなるようだ。

これで、使えるものは入手できることが分かった。

  • ただ、ベータ版で、最新の 1つの バージョンしか入手できないような.. 正規版(相当)か 特定のバージョン(の zip 版)を入手するのはどうしたら良いのだろう?
  • あと toolchain のソースコードの入手方法もまだ分かっていない。バイナリよりむしろこっちの方が欲しい。(WinAVR だとパッチ一式が一緒に入っていて 便利だったのに これにはパッチ集は入っていない。)
  • だいぶ不便になった印象。ただ Linux 版が手に入ることは良いことだ。あまり考えなくとも 使えるし同じバイナリが生成できる。

とりあえず、事情がわかるようになるまで、取ってきた次のバージョン

  • AVR32 Studio 2.7.0.851 (Toolchain 3.1.0.201012011657)
  • avr-gcc -v では、gcc version 4.4.3 (AVR_8_bit_GNU_Toolchain_3.1.0_200)

を試しに使ってみようかと思う。

リリースするバイナリでは、WinAVR-20100110 を 使うが、Tiny10 を使ってみるとか Xmega を使ってみるとかするときに必要だ。特に興味があるのは、Tiny10 だったりする。FPGA で遊ぶときに これに準拠して小さなコアにしたい。

    追記 2011/03/02: 3.1.0_200 を Tiny10 で試してみたが、使えるレベルになっていないことが判った。そして それ以降のバージョンは現在公開されていない。待つしかないようだ。

    追記 2011/03/08: AVR Studio 5 beta が出ている(523MB: サイズ注意)。

    これをインストールすると、AVR Toolchain もインストールされる。入っているのを見てみると

    gcc version 4.5.1 (AVR_8_bit_GNU_Toolchain_3.2.0_253)

    になっている。これだけを 取り出して MSYS のコマンドラインで使ってみたのだが、少々具合が悪い。-lgcc が見つけられなくてエラーになる。しょうがないので gcc フロントエンドだけ 3.1.0 (200) の avr-gcc を使っている。
    ( lib/gcc/avr/4.5.1 とlibexec/gcc/avr/4.5.1 を 4.4.3 に rename する。こと)

    で、tiny40 を試してみたが、まだだめ。32bit の LDS/STS は使わなくなったが、string など初期値付きデータが FLASH から RAM にコピーされないようだ。

    0 で初期化されたデータがあれば、<__do_clear_bss> が call されるが、0 以外で初期化すると なにも call されなくなる。この問題は、自分で初期化すれば良さそうなのだが、今度は 32bit の STSが使われる。当面グローバル変数は使えなさそう。

    無理やりでも使いたいのであれば、auto 変数を使い。初期値は、コードで代入するという手を使う。それ以外に、妙にコード効率が悪いという問題がある。int8_t で指定しているのに 16bit 演算しているとか ... 。

    追記: 2011/03/17:

    http://distribute.atmel.no/tools/opensource/avr-gcc/

    パッチはここ?

Tiny10 系について:

Tiny10 では、レジスタが r16-r31 の 16個しかない。 AT90S1200 や XMEGA を含む数あるAVRのなかで、このシリーズだけ違うのである。そして、Atmel は頑張って gcc をこれにも対応させた。AVR Toolchain が動くようなので、どうやって少ないレジスタに対応したのかチェックしてみようと思う。

    参考リンク : アセンブラ関数の書き方(avr-gcc)

  • レジスタ:

    普通のAVRでは、いくつか特定の役割を持ったものがある。

      r31:r30 Z レジスタ
      r29:r28 Y レジスタ (フレームポインタ)
      r27:r26 X レジスタ
      r1 tmp
      r0 zero

    X/Y/Z レジスタは ポインタとして(も?)使われる。r1 は、LPM 系, MUL 系の命令で使われる。r0 は、C では常に 0 を入れておくルール。

    tiny10 では、r1 は存在しないが、LPM 系, MUL 系の命令もまた存在しないから無問題。r0 も 存在しないが、ないなら使わないで済ませば良い話のようだ。

  • 引数:

      r25:r24 第一引数
      r23:r22 第二引数
      r21:r20 第三引数
      r19:r18 第四引数

    普通のAVRでは、4 つまでの引数がレジスタ渡しになる。それ以上はメモリに置き、Y レジスタ(フレームポインタ)を使いアクセスする。なお、8bit の場合でも詰めることはしないで 16bit レジスタのように使っている。

    tiny10 では、3 つまでに変わった。

    追記: 普通のAVR で 4 つまでと書いたが、間違い。r25:r24 まで続くようだ。

  • 戻り値

      8bit r24
      16bit r25:r24
      32bit r25:r24:r23:r22

    引数に使ったレジスタを戻り値に使っている。これは、tiny10 でも変わらない。

  • call される側が値を保証するレジスタ

      r29:r28 Y レジスタ
      r17 - r2
      r0 (0 を設定)


    普通のAVR では、こうなっていて 使用する場合は push し pop で値を戻す。

    tiny10 は、調査中だが、

      r29:r28 Y レジスタ
      r17 - r16

    こうなっている。

    ところで、r1 (__zero_reg__) / r0(__temp_reg__) はどうしているのか?

      gcc のコード生成を見て分かったのだが、必要なのである。過去のAVR のコード生成に影響を与えずに改造しなくてはならないので、基本的な考えを変更するわけにはいかないのだ。

      で、どういうわけか、r17 , r16 を割り当てている。セーブ不要のレジスタにすべきではないか? 幸い引数を 3 つまでにしたので、r19/r18 はこの目的に使えるはずだ。


  • その他 Tiny10 が違う点

    命令セットやレジスタとは関係ないのだが、gcc に関係しそうなところで Tiny10 が違うところがある。

    Tiny10 では LPM 命令がないが、フラッシュ全体が 通常メモリと同じようにアクセスできる。ただし、アドレスはずれていて 0x4000 から フラッシュが始まる。

    これ gcc ではどう扱っているのか 要調査。

    ついでに書いておくと メモリ(RAM)のアクセスが遅いらしい。2 clock に 1 回アクセスとか。アドレス空間に フラッシュとか いろいろ 入ったせい?

  • avrXX

    普通 avr3 とか avr5 とか CPU の種類によってカテゴライズし、libgcc.a を切り分けている。

      (avr2) avr25 avr3 avr31 avr35 avr4 avr5 avr51 avr6

      XMEGA 以外でも 従来のものは、これだけある。 アドレススペース x tiny/mega で分類されていたと思う。ちなみに at90s2313 などは avr2 で ディレクトリがなく、直下の libgcc.a を使う。

    tiny10 は、avrtiny10 になっている。avr0 とかするのかと思ったのだが、安易なネーミングだった。ちなみに、tiny20/tiny40 も avrtiny10 を使う。

    ついでに書くと XMEGA は、avrxmega2,4,5,6,7 と大幅に増えている。なにやら大変なことになっているようだ。

    リストするとこう。

    mmcu=atxmega16a4 mmcu=avrxmega2;
    mmcu=atxmega16d4 mmcu=avrxmega2;
    mmcu=atxmega16x1 mmcu=avrxmega2;
    mmcu=atxmega32d4 mmcu=avrxmega2;
    mmcu=atxmega32a4 mmcu=avrxmega2;
    mmcu=atxmega32x1 mmcu=avrxmega2;
    mmcu=atxmega64a3 mmcu=avrxmega4;
    mmcu=atxmega64d3 mmcu=avrxmega4;
    mmcu=atxmega64a1 mmcu=avrxmega5;
    mmcu=atxmega64a1u mmcu=avrxmega5;
    mmcu=atxmega128a3 mmcu=avrxmega6;
    mmcu=atxmega128b1 mmcu=avrxmega6;
    mmcu=atxmega128d3 mmcu=avrxmega6;
    mmcu=atxmega192a3 mmcu=avrxmega6;
    mmcu=atxmega192d3 mmcu=avrxmega6;
    mmcu=atxmega256a3 mmcu=avrxmega6;
    mmcu=atxmega256a3b mmcu=avrxmega6;
    mmcu=atxmega256d3 mmcu=avrxmega6;
    mmcu=atxmega128a1 mmcu=avrxmega7;
    mmcu=atxmega128a1u mmcu=avrxmega7;

    基本的に アドレススペースの関係で、分類されているようだ。A1U とか X1 , B1 とか知らないものがあるが、いずれ世に出るのだろう。


追記: Tiny40 の I/Oレジスタマップ

ここに書くのもどうかと思うが、FPGA で遊ぶ準備として Tiny40 のレジスタを調べてみた。ADCとか NVM とか FPGA から見て関係ない物は除外してある。

なぜ Tiny40 ? かというと (1)ピンの数が多く PORT が多く割り当てられている。(2)SPI/TWI がある。
これから不要なものを取って USART 追加すれば、だいたい欲しいものになる。

ステータスレジスタ, スタックポインタ 以外は基本的にどこになにをマップしても良いのだろうけれど、全然違うとやはり AVR らしくなくなる。合わせられるものなら合わせた方が無難だろう。


    0x3F SREG ---- ステータスレジスタ(必須)
    0x3E SPH +--- スタックポインタ(必須)
    0x3D SPL +
    0x3C CCP ---- レジスタ書き換え保護

    0x3A MCUCR ----
    0x39 OSCCAL +--- クロック関係
    0x38 reserved :
    0x37 CLKMSR :
    0x36 CLKPSR +
    (0x35 - 0x32)
    0x31 WDTCSR ---- ウォッチドックタイマ

    0x30 SPCR +--- SPI
    0x2F SPSR |
    0x2E SPDR +

    0x2D TWSCRA +--- TWI
    0x2C TWSCRB |
    0x2B TWSSRA |
    0x2A TWSA |
    0x29 TWSAM |
    0x28 TWSD +

    0x27 TCNT1H +--- タイマカウンタ1 (16bit)
    0x26 TIMSK :
    0x25 TIFR :
    0x24 TCCR1A |
    0x23 TCNT1L |
    0x22 OCR1A |
    0x21 OCR1B +

    0x20 RAMAR
    0x19 RAMDR

    0x1E PUEC +--- ポートC
    0x1D PORTC |
    0x1C DDRC |
    0x1B PINC +

    0x1A PCMSK2

    0x19 TCCR0A +---- タイマカウンタ0 (8bit)
    0x18 TCCR0B |
    0x17 TCNT0 |
    0x16 OCR0A |
    0x15 OCR0B +
    ( 0x14 - 0x0D )
    0x0C GIMSK
    0x0A PCMSK1
    0x09 PCMSK0
    ( 0x08 )

    0x07 PUEB +--- ポートB
    0x06 PORTB |
    0x05 DDRB |
    0x04 PINB +

    0x03 PUEA +--- ポートA
    0x02 PORTA |
    0x01 DDRA |
    0x00 PINA +

    USART レジスタ ( 0x14 - 0x0D に入るか) 
    +0x6 UDR1
    +0x5 UBRR1H
    +0x4 UBRR1L
    +0x3 UCSR1D (optional)
    +0x2 UCSR1C
    +0x1 UCSR1B
    +0x0 UCSR1A


    並べてみて気になったのは、

  • CCP というのは、4 クロック以内の書き込まないとダメという機能を一ヶ所にしたもの。

  • CLKMSR は、クロックソースを切り替えるもの。

  • PORT に PUE というのが追加されていること。これは プルアップ許可機能が DDR から独立。
    .. こうなっていると、PORT を 0 にして DDR 操作で I2C のような操作がでできる。

  • RAMAR/RAMDR とは何? なぜ必要?


追記: 2011/10/13 -- このページを見ている人がいるようなので

  • AVR互換コア(テスト3)

    その後、tiny10 系 と 互換のコア(FPGA 用 IP)を実際に作っている。テストも出来ないので、AVR_Toolchain は、独自に 修正することにした。その暫定結果が、上の記事。

  • AVR_Toolchain-20110424-src.tar.gz

    これが、ソースへのパッチ集。

  • binutils も 1 バイト LDS/STS に対応するために修正が必要。
  • __tmp_reg__ , __zero_reg__ は r18/r19 に define している。これは重大な修正だが、こうしないと libgcc の 関数で対応できないものが出る。
  • avr-libc は、ほとんど対応できていない。アセンブラが多すぎて対応しきれないのだ。

    4/24 で止まっているが、その後 AVRStudio 5 が出ている。ソースがどうなったかチェックはしていない。
  • posted by すz at 03:53| Comment(0) | TrackBack(0) | 日記