2011年05月20日

AVR互換コア(FIFOモジュール)

少し大きめの FPGA なら AVR互換コア(rtavr) を複数インプリメントできる。

その時に、rtavr 同士が通信できるモジュールとして FIFO モジュールを検討してみた。

    突然こういうことをやり出したのには、理由がある。それについては別記事にする。

    FIFO モジュールの説明は、

  • XAPP256

    に書いてあるのだが、このインターフェイスを参考に 一般の Verilog で記述してみた。

    実装方式として、Dual Port 分散RAM による方式(以下 DPORT) と シフトレジスタによる方式(以下 SHIFT) の 2 つを考えた。

    DPORT 方式は、Dual Port 分散RAM をサポートしている FPGA なら素直に記述すれば、推論してくれるはず。SHIFT 方式は、generate を使って二重ループという .. なんだか複雑な記述になってしまった。成功すれば、DPORT 方式より コンパクトになるが、失敗すると 全部 FF にされて 規模が増えてしまう。



これは、シミュレーション結果。


// Target Device: xc3s200a-4ft256
// Product Version: ISE 12.4
// Design Goal: Balanced
// SHIFT DPORT
// Number of Slice Flip Flops: 12 19
// Number of 4 input LUTs: 20 39
// Number used as Shift registers: 8 -
// Number used for Dual Port RAMs: - 16
// Number of occupied Slices: 14 26
// Number of bonded IOBs: 26 26
// Number of BUFGMUXs: 1 1
// Post-PAR Static Timing Report
// Maximum frequency(MHz): 114.077 125.691
//

SHIFT 方式だと、14 スライスで済んだ。

    最初に作ったのは、9 スライスだったのだが、COUNT 出力を付けたりして使いやすい仕様にした結果 + 5 スライス増えた。
    SHIFT 方式について肝心な部分だけ転載すると ..

    assign OUT = r_out;
    assign EMPTY = ( r_pos == 4'hf );
    assign FULL = ( r_pos == 4'he );
    wire [3:0] fifo_count = r_pos + 1;
    assign COUNT = fifo_count;
    always @(posedge CLK)
    begin
    if (CLR) r_pos <= 4'hf;
    else
    begin
    if (WR & RD)
    begin
    end
    else if (RD)
    begin
    if (~EMPTY) r_pos <= r_pos - 4'h1;
    end
    else if (WR)
    begin
    if (~FULL) r_pos <= r_pos + 4'h1;
    end
    end
    end
    always @(negedge CLK)
    begin
    if (~EMPTY) r_out <= fifo[r_pos];
    end

    generate
    genvar i,j;
    for (i=0; i<WIDTH; i = i+1)
    begin : data_in
    for (j=1; j<16; j = j+1)
    begin : data_in_bit
    always @(posedge CLK)
    begin
    if (WR) fifo [j][i] <= fifo[j-1][i];
    end
    end
    always @(posedge CLK)
    begin
    if (WR) fifo [0][i] <= IN[i];
    end
    end
    endgenerate

    なにはともあれ、これはうまくいった。


さて、これを使った、AVR のモジュールの仕様を考えてみる。

    まず、レジスタや 割り込みをあまり使いたくないという事情がある。空きが少なくて 厳しいのだ。それに複数付けたくなるかも知れない。最低限のリソースで済むようにしないと。

    次に、機能は送受信。相手も同じモジュールを使う。で、FIFO をどちら側に付けるか --これは送信側ということにする。

  • 割り込み

    USART などは、3 種類も割り込みを使っている。が、これを 1 つで済ます。

    割り込みの意味は、NOTIFY で CPU で IOR に書きこんで発生させる。割り込みを受けた側が スタータスを見てなにをすべきか判断する。

    割り込み許可のフラグも必要だから、レジスタを 2 bit 使う。

  • データレジスタ

    これは、USART の UDR のようにREAD すれば受信データが読めて、WRITE すれば送信データを 書きこむ ことにすれば良さそうだ。

  • ステータス

      受信データがある
      送信中(相手が全部を受け取っていない)
      送信が可能(空きがある)

    これぐらいは必要そうだ。これで、合計 5 bit 。

    あと、送信バッファがどれぐらい空いているのか も知りたい。送信中フラグ と 送信可能フラグをやめて 4 bit の情報にしよう。-- この変更で 合計 7 bit 。

  • コントロール

      送信データの破棄
      NOTIFY 割り込みの送出

    ぐらい? あと、NOTIFY 割り込みを相手が受け取ったかどうかの情報が欲しい。これはステータスに入れる。

さて、こんな仕様などより悩ましいのは、名前。-- 名前を付けないとファイルも作れない。何にしよう。

    機能的には、通信ポート。... CPI(Communication Port Interface) ということにして、モジュール名は rtavr_ior_cpi 。

    あとはなんでもかんでも CP を付ける。

    レジスタ名は、CPCSR (CP Control and Status Register) , CPDR (CP Data Register)

    フラグ名は沢山ある。

    Communication Port Interface(CPI):

    +-------+-------+-------+-------+-------+-------+-------+-------+
    0x09 | CPIR | CPIE | CPIS | CPRXS | CPTXS     |
    +-------+-------+-------+-------+-------+-------+-------+-------+

    +-------+-------+-------+-------+-------+-------+-------+-------+
    0x0a | CPDR |
    +-------+-------+-------+-------+-------+-------+-------+-------+

    CPIR : CP Interrupt Recv. Flag
    CPIE : CP Interrupt Enable Flag
    CPIS : CP Interrupt Send Flag
    CPRXS : CP Recv. Status (1: Recieved)
    CPTXS : CP Trans. Status (xxx0 : Empty , 1xxx : Full )

    こんな感じか。CPTXS は ちょっと細工。2bit で 詰まり具合が分かるようにする。

    Control の方は

    • CPTXS[0] に 1 を書くと バッファを破棄。
    • CPIS に 1 を書くと 割り込みを送出して、受け取られたら 0 に戻る。
    • CPIR / CPIE は、AVR のほかの装置と同じようにする。(詳細未定)


実装完了

    // Target Device: xc3s200a-4ft256 , top-level rtavr
    // SHRINKED DPORT SHIFT
    // Number of Slice Flip Flops: 388 407 403
    // Number of 4 input LUTs: 1089 1173 1162
    // Number of occupied Slices: 662 710 699
    // Number used as a route-thru: 34 35 35
    // Number used for Dual Port RAMs: 16 32 16
    // Number used as Shift registers: - - 8
    // Number of bonded IOBs: 12 36 36
    // IOB Flip Flops - - -
    // Number of BUFGMUXs 1 1 1
    // Number of RAMB16BWEs 3 3 3
    // Number of DCMs - - -
    // Number of BSCANs - - -
    // Post-PAR Static Timing Report
    // Maximum frequency(MHz): 46.198 43.459 42.531


    SHIFT で +37 スライス / DPORT で +48 スライス。

    output [7:0] CPI0_TXD : 送信データ
    output CPI0_TX : 送信データあり
    input CPI0_TX_ACK : 送信データあり ACK
    output CPI0_IXS : 割り込み送信
    input CPI0_IXS_ACK : 割り込み送信 ACK

    input [7:0] CPI0_RXD : 受信データ
    input CPI0_RX : 受信データあり
    output CPI0_RX_ACK : 受信データあり ACK
    input CPI0_IXR : 割り込み受信
    output CPI0_IXR_ACK : 割り込み受信 ACK

    信号線は、こんな風に定義した。クロックは共有しているのが前提。
    送信/受信は、対称になっていて、上と下をたすきがけ(クロス)で接続する。

    データそのもの以外の信号線は、全部ハンドシェークする。ACK は、posedge_CLK_180 で受け取り。

    規模は小さいのだが、rtavr に組み込むのは、ものすごく面倒だった。
    組み込み方法が 多数あるので、それに対応しないといけないし、接続用の信号も rtavr_fifo - rtavr_ior_cpi - rtavr_ior - rtavr と 3 段もパススルーしないといけない。

    それは、ともかく ... これでプロセッサ間通信のしくみが確立できた。次の記事『AVR互換コア(SMP化)』に続く。
posted by すz at 23:32| Comment(0) | TrackBack(0) | AVR_CORE
この記事へのコメント
コメントを書く
お名前: [必須入力]

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

ホームページアドレス:

コメント: [必須入力]

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


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

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