2011年05月06日

AVR互換コア(UCF,コンフィグファイル)

AVR互換コア(ver 1)は、完成させたつもりだったのだが、実際に FPGA のコンフィグファイルを作るところでハマっている。

入力専用ピンには、PORT を割り当てられない -- という問題も出ている。

しばらく、AVR互換コアのカテゴリで続けようと思う。

UCFファイル

    前記事で書いたが、上記の問題は解決した。今の UCF ファイルはこうしている。


    #pin2ucf - Thu May 05 20:52:49 2011
    #The following constraints were newly added
    NET "CLK2X" LOC = "P44"; # GCLK1 (8MHz or 6/12/24/48 MHz )
    NET "CLK" LOC = "P41"; # GCLK15 (NC)
    NET "PW_SLEEP" LOC = "P31"; # VS0 (LED)
    NET "RESET" LOC = "P23"; # M1 (LED)
    NET "PORTC<0>" LOC = "P27"; # CSO_B (FLASH /S)
    NET "PORTC<1>" LOC = "P53"; # CCLK (FLASH C)
    NET "PORTC<2>" LOC = "P51"; # DIN (FLASH DO)
    NET "PORTC<3>" LOC = "P29"; # VS2 (LED)
    NET "PORTC<4>" LOC = "P46"; # MOSI (FLASH DIO)
    NET "PORTC<5>" LOC = "P7"; # IP_3 (RX)
    NET "PORTC<6>" LOC = "P34"; # (TX)
    NET "PORTC<7>" LOC = "P24"; # M2 (LED)

    M1/M2 , VS0/VS2 は、H で点灯する。M1/M2 の LED は、コントローラと共用で使わないのが基本。
    CLK,PW_SLEEP は信号を出すつもりがなかったのだが、rtavr が top-level なので出てしまっている。これもデバッグ用で使わないのが基本。

    PORT で操作できるのは、VS2 のみ。もちろんデバッグ用。

    CLK2X は コントローラから受け取る。MEGA32U2 だと 8 MHz 固定。AE-UM232R だと 6/12/24/48 MHz 。

    FLASH のアサインは固定のはずなので、残りで ボードに合わせる必要があるのは、TX/RX のみ。

    自作の artemis ボード向けだが、この程度ならボード専用という感じではない。artemis のカテゴリにしようと思ったが AVR互換コアの延長と位置づける。

    ところで、artemis ボード自体の UCF ファイルは、別に作った。

    こちらは、top-level の module とのセット。SPI FLASH ライタは、rtavr を直接 top-level にする。

ハマった理由?

    忘れていたが、私の環境は、完全なものではなかった。

    SSD の netpc を使っているので容量が厳しく、使わなさそうなファイルを削除していたのだった。PlanAhead すらまるごと削除。バックアップは取ってあるが、ピンポイントで足りないファイルを戻すのならともかく、全部を戻すのはとても嫌 -- というか無理。

    まともにインストールしたマシンで試してみて、うまくいくようなら完全に環境の問題。

Ver wk11



  • rtavr-wk11.tar.gz

    これをベースにする。

    変更点は、ROM のライトプロテクト機能の追加(IOR_HAVE_NVM)と gpr の小変更。

      gpr_16 の dual-port 分散 RAM が 32 と倍になっていた。

      < wire [7:0] v_DOBH = gpr[r_addrb];
      ---
      > wire [7:0] v_DOBH = DOB;
      142c142
      < assign JA[11:8] = gpr[r_addrb][3:0];
      ---
      > assign JA[11:8] = DOB[3:0];
      192c192
      < if (~CLK) s1_DOBL <= gpr[r_addrb];
      ---
      > if (~CLK) s1_DOBL <= DOB;

      wire は、C の define のようなものと思って使っていたが、ちょっと違うらしい。gpr[r_addrb] を複数の場所で参照すると 32 になったのだ。一旦 wire でまとめると 16 に戻る。規模も減った。

      gpr_16w は 80 で想定どおりだが、同じように変更。

    それ以外に TOPレベル用の UCF ファイルなどを追加。artemis ボード用だが リファレンスということで。

    rtavr.ucf は上記のものだが、変更予定。rtavr を TOPレベルにすると BSCAN を入れられない。

      別記事で検討したが、BSCAN_SPARTAN3 プリミティブを使うと JTAG に SPI スレーブなど接続できるらしい。


ISP 機能を設計してみた。

    FPGA の Implement は時間がかかるし面倒。プログラムだけを書き換えられた方が良さそう。ログを抜いて来ることでデバッグにも使える。

    // SIN 0aa1 aaaa XXXX XXXX <<< MOSI stream (MSB first)
    // XXXX XXXX load_data <<< MISO stream (MSB first)
    //
    // SOUT 1aa1 aaaa store_data
    // XXXX XXXX XXXX XXXX
    //
    // SSTPR 0110 100a PR[a]
    // XXXX XXXX XXXX XXXX
    //
    // SLD 0010 0I00 XXXX XXXX ( if I == 1 , PR = PR +1 )
    // XXXX XXXX load_data
    //
    // SST 0110 0I00 store_data ( if I == 1 , PR = PR +1 )
    // XXXX XXXX XXXX XXXX

    こういうコマンド仕様で、Tiny40 の TPI をベースにして決めた。

      基本は、アドレスポインタの設定をする SSTPR と、64K 空間から 1 バイト読み書きする SLD/SST 。これだけで十分なのだが、IOR 専用の SIN/SOUT も付けてみた。

      TPI はその他に、初期化を行うための SKEY , SLDCS/SSTCS 命令がある。それらを使ったシーケンスなしに、いきなり使えるようにした。ただし、JTAG 側で使えるようにするためのシーケンスは必要。

      SIN/SOUT はアドレス幅が小さいだけ。SLD/SST でも IOR , RAM にアクセスできる。

      .. といっても。IOR は RESET 中は 普通 値を変更できない。例外は、NVM で、ROM の ライトプロテクトの解除機能だけが使える。

      ちなみに、NVM は、NVMCMD に 0x1d を書くと、ライトプロテクトが解除されて、NVMCSR が 0x80(初期値)が 0 になる仕様にしている。プログラムでも使用できるので、ログを ROM に残すことが出来る。

    ISP へのアクセスは、SPI 。TPI はシリアルがベースで LSB First だが、普通に MSB first にした。
    コマンドは全部 2 バイト。1 バイト送ったら 次に1 バイトのデータを 送るか受けるかする。

    CS(正論理) が一旦 L になると、内部の状態(bit数カウンタ)がリセットされる。

    rtavr 側は、リセット中だけ バスを開放する。RESET と SPI の CS を連動させるつもり。

      書き込み終了まで RESET 状態が続いてくれないと困るのだが、JTAG の仕様をちゃんと理解していないので、この仕様で良いか少々不安。


    no SIN/SOUT
    Number of Slice Flip Flops 52 45
    Number of 4 input LUTs 63 47
    Number of occupied Slices 52 39
    Total Number of 4 input LUTs 78 62
    Number of bonded IOBs 39 39
    Number of BUFGMUXs 1 1

    規模は、こんな風になった。FF の数は、reg として定義している bit数の合計と一致する。

    SIN/SOUT が不要だと気がついて削ってみたら 13 スライス減った。

トップレベルに ISP と rtavr を Implement


    BSCAN_SPARTAN3A bscan (
    .RESET(BSCAN_RESET)
    , .SHIFT(BSCAN_SHIFT)
    , .CAPTURE(BSCAN_CAPTURE)
    , .UPDATE(BSCAN_UPDATE)

    , .TDI(TDI)
    , .TCK(TCK)
    , .TMS(TMS)

    // signals for USER1
    , .DRCK1(DRCK1)
    , .SEL1(SEL1)
    , .TDO1(TDO1)

    // signals for USER2
    , .DRCK2(DRCK2)
    , .SEL2(SEL2)
    , .TDO2(TDO2)
    );

    BSCAN_SPARTAN3Aの信号線は、こんな風になっている。それを ISP に次のように接続してみた。

    isp ISP (.CLK(CLK)
    , .MOSI(TDI)
    , .SCK(DRCK2)
    , .CS(SEL2)
    , .MISO(TDO2)

    , .ISP_STORE(ISP_STORE)
    , .ISP_LOAD(ISP_LOAD)
    , .ISP_ADDR(ISP_ADDR)
    , .ISP_STORE_DATA(ISP_STORE_DATA)
    , .ISP_LOAD_DATA(ISP_LOAD_DATA)
    );

    rtavr は、こう。ISP_XX は、相互に接続しているだけ。

    rtavr RTAVR (.RESET(RESET), .CLK2X(CLK2X)
    , .CLK(CLK)

    , .DDR(DDR[23:0])
    , .PORT(PORT[23:0])
    , .PIN(PIN[23:0])

    , .ISP_STORE(ISP_STORE)
    , .ISP_LOAD(ISP_LOAD)
    , .ISP_ADDR(ISP_ADDR[15:0])
    , .ISP_STORE_DATA(ISP_STORE_DATA[7:0])
    , .ISP_LOAD_DATA(ISP_LOAD_DATA[7:0])
    );

    さて、問題のひとつは、RESET 。JTAG でデバッグしている間は外部リセットを考えなくてよいだろう。だが、候補は 2 つある。BSCAN_RESET と SEL2 とどちらを使うのが良いのだろう?

    wire RESET = BSCAN_RESET;
    wire CLK2X = CLK2;

    とりあえずこんな風にした。クロックは、HOST インターフェイスからもらう。

    で、rtavr の接続。

    assign VS0 = DDR[19] ? PORT[19] : "H";
    assign PIN[19] = VS0;
    assign VS2 = DDR[23] ? PORT[23] : "H";
    assign PIN[23] = VS2;
    `ifdef IOR_HAVE_SPI
    assign PIN[`SS_BIT] = SEL1;
    assign PIN[`SCK_BIT] = DRCK1;
    assign PIN[`MOSI_BIT] = TDI;
    assign TDO1 = PORT[`MOSI_BIT];
    `endif
    `ifdef IOR_HAVE_USART
    assign PIN[`RX_BIT] = TXD;
    assign RXD = DDR[`TX_BIT] ? PORT[`TX_BIT] : "H";
    assign PIN[`TX_BIT] = RXD;
    `endif

    USER1 の方を SPI スレーブとして接続し、LED が付いている VS0/VS2 に PC3/PC7 を接続してみた。( SPI / USART が PORTC に割りつけられていて PC3/PC7 だけ空いている)

    次の問題は、規模。+40 スライス以上増えるのだから、今までの 50A の設定では無理。SPI(SLAVE) と USART のどちらかだけ構成するなら、余裕なのだが... 片方が動いたなら、もう片方のデバッグに使いたい。

    Implement してみたところ 722 スライスだった。もうすこしだから、デバイスの設定を変えることで入らないかやってみよう。


      追加:
      `define RTAVR_PORT_ESCALATION

      上記のような DDR/PIN/PORT に分離するインターフェイスの指定

      変更前:
      `define FIXED_MSTR 1 // 1: Master 0: Slave
      変更後:
      `define FIXED_MSTR 0 // 1: Master 0: Slave

      これは、SPI を Slave 専用にする設定。ここまでは最初から変更している。

      変更前:
      //`define FIXED_OCR0B 127 //
      `define FIXED_OCR0A 128 //
      変更後:
      `define FIXED_OCR0B 127 //
      `define FIXED_OCR0A 128 //

      これは、OCR0A/OCR0B ともに固定値にするもの。

      削除:
      `define PORT_HAVE_PIN_WRITE

      PIN への Write で PORT を反転する機能 -- 必要ない。

      追加:
      `define FIXED_SPR 0 // 0: 1/2 CLK , 1: 1/4 CLK 2: 1/8 CLK

      Slave 専用なので、クロック生成しない : 固定で良い。

      変更前:
      `define UBRR_BITS 8 // boud parameter (2 - 16)
      変更後:
      `define UBRR_BITS 7 // boud parameter (2 - 16)

      UBRR のビット数を減らす。1 減らすと内部カウンタも減る。

      -- ちょっと計算。CLK2X を 33MHz として CLK 16.5 MHz 。1/8 (U2X =1) なら、7bit あれば 最小 16.1 Kbps 。19.2 Kbps にするには、分周比は (UBRR - 1) だから、106 を設定する。8 MHz なら 25 で 12 MHz なら 38 。
      値を固定にできるオプションもあって、たとえば、

      `define FIXED_UBRR 106

      とすると 4 スライス稼げる。

    これで 702 になって 50A に入るようになった。

    だがもうすこし稼いでおきたい。

    ... といっても今まで散々チューニングしてきたのだ。なかなかすぐには出てこない。UBRR をあれこれしても浮くのはほんの僅か。

    しょうがないので、

    `define IOR_NO_COMPA // tempolary shrinking option
    `define IOR_NO_COMPB // tempolary shrinking option

    を作ることにした。これで、2 つ割り込みを減らす。-8 スライス。

  • rtavr-wk11b.tar.gz

    スナップショット。isp_sample ディレクトリを新設して、実際のボードのインプリメントを始めた。

    あと、RAM_WIN の機能を シミュレータに仕込んだ。これだけ、デバッグができていないので確認したかったのだが、目視は面倒。SREG のたぐいだと思えば CPU 専用シミュレータに仕込んでも変ではないだろう。

    ところで、最小規模がどれぐらいになるか気になったので、見てみることにした。

    base (- ldd/std) old-alu old-old-alu
    Number of Slice Flip Flops 228 223 229 233
    Number of 4 input LUTs 825 804 800 827
    Number of occupied Slices 475 465 464 482
    Total Number of 4 input LUTs 849 832 827 855
    Number used as a route-thru 24 28 27 28
    Number used for Dual Port RAMs 16 16 16 16
    Number of bonded IOBs 12 12 12 12
    IOB Flip Flops 1 1 1 1
    Number of BUFGMUXs 2 2 2 2
    Number of RAMB16BWEs 3 3 3 3
    Maximum frequency:(MHz) 54.437   54.460 51.584 50.005

    INT0 と PORTC のみのデバイス構成で、LDD 命令の拡張は入れる。port は bit反転機能を外している。これが基本。LDD 命令なしが、コンパイラのデフォルトだから、もうすこし減らせる。... といっても僅か 10 スライス。これで 20% 命令数が減るのだからお得だ。

    さて、ALU を module 化したわけだが、以前のに戻すとどうなるか? さらに -1 だが、遅くなった。-- だが、今の ALU はちょっといじってあるから、アンフェア。さらに 最初の ALU として独立していないのは、どうだったか。... というと 現状から見て +17 スライス。

    改めてみると、随分良くなっているのだな。ALU だけで 3 種類もあるのはどうかと思うので、module 化版ひとつだけにするか。

(続く)
関連記事:

著作権について

    ここで提示しているコードは正しく動作しないとはいえ、既に著作権は発生しています。
    著作権は、すzが保持しており放棄はしていません。

    教育目的および私用目的では、もともと著作権の範囲外なので自由につかえます。また、ライセンスとして、GPL を適用しています。GPL に従う範囲において 個別の許可なく使用することができます。許諾のための連絡も不要です。

    なお、GPL なので、生成したバイナリを作り直せる範囲のソース開示が必要になります。FPGA だと 通常 チップ全体になってしまいます。また、開示したソースを GPL の範囲で再利用されることを妨げることはできなくなります。このコードを利用する場合この点に留意してください。

    個別の許可を得れば、GPL 以外の条件での使用は可能です。が、作業中のものには許可は出さない予定です。作業が完了(もしくは中断)したとき、ライセンスは見直します。

    なお、すでに公開してしまったものの、ライセンスを取り消すことはできないと考えていますが、ライセンスの追加は可能です。また、新しく公開するものについては、ライセンスしないことすら可能で、どのような制限もありません。変更する可能性がありますので、この点にも留意してください。
posted by すz at 11:36| Comment(0) | TrackBack(0) | AVR_CORE
この記事へのコメント
コメントを書く
お名前: [必須入力]

メールアドレス: [必須入力]

ホームページアドレス:

コメント: [必須入力]

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
この記事へのトラックバックURL
http://blog.sakura.ne.jp/tb/44904483
※ブログオーナーが承認したトラックバックのみ表示されます。

この記事へのトラックバック