SSブログ
-| 2012年04月 |2012年05月 ブログトップ
前の10件 | -

Vivado発表 [HDL]

Xilinxの次世代ツール、Vivadoが発表されました。
C/C++/SystemC辺りは「ハイレベル合成」のライセンスが必要らしい。これってAutoESLかな?お値段ちょっとお高い?といっても50万ぐらい。ちょっと前からしたら格安の値段だと思います。
WebPackでもSystemVerilog使えるなら、QuartusIIはだいぶ前からsv使えるので、svメインにしても良いかな~

Vivadoって名前聞いたとき、もちろん「ビビデ・バビデ・ブー」からもじったんだと思いましたよ(笑)。こっちはBでVじゃないですが。

部品:AXIストリームレジスタ シミュレーション [AXI]

axis_sliceをシミュレーションしてみます。

テストパターン発生に先のaxis_source,axis_sinkを使います。で、早速変更してしまってます。Xilinxのisim(無償版)を試してみたのですが、「input wire integer ratio」の構文が通らなかったので、ratioを内部変数にしてます。そういえば元々この構文変だなぁと思いながらもModelSim(Altera版)では通っちゃってたので、まぁいっかで放ってた物でした。
「実体名.ratio<=値」の形で変更します。

axis_source、ソース側
module  axis_source
(
    input   wire  enable,   // enable
    input   wire  c_clk,    // Clock
    input   wire  c_rst,    // Reset
    input   wire  m_ready,  // Ready
    output  wire  m_valid   // Valid
);
    integer ratio;  // ratio

    reg   [3:0]  rand;
    reg   inhib;
    reg   valid;

    assign  m_valid = valid & ~inhib;

    always @(posedge c_clk) begin
        if (c_rst) begin
            valid   <= 1'b0;
            rand    <= 0;
            inhib   <= 1'b1;
        end
        else begin
            valid    <= enable;
            if (inhib | m_ready) begin
                rand    = $random;
                case (ratio)
                    default  : inhib    <= 0;
                    1        : inhib    <= &rand[3:0];
                    2        : inhib    <= &rand[2:0];
                    3        : inhib    <= &rand[1:0];
                    4        : inhib    <=  rand[0];
                    5        : inhib    <= |rand[1:0];
                    6        : inhib    <= |rand[2:0];
                    7        : inhib    <= |rand[3:0];
                endcase
            end
        end
    end
endmodule

axis_sink、シンク側
module    axis_sink
(
    input   wire  enable,   // enable
    input   wire  c_clk,    // Clock
    input   wire  c_rst,    // Reset
    output  wire  s_ready,  // Ready
    input   wire  s_valid   // Valid
);
    integer ratio;  // ratio

    reg   [3:0]  rand;
    reg   inhib;
    reg   ready;

    assign  s_ready = ready & ~inhib;

    always @(posedge c_clk) begin
        if (c_rst) begin
            ready    <= 1'b0;
            rand     <= 0;
            inhib    <= 1'b0;
        end
        else begin
            ready    <= enable;
            rand     = $random;
            case (ratio)
                default  : inhib    <= 0;
                1        : inhib    <= &rand[3:0];
                2        : inhib    <= &rand[2:0];
                3        : inhib    <= &rand[1:0];
                4        : inhib    <=  rand[0];
                5        : inhib    <= |rand[1:0];
                6        : inhib    <= |rand[2:0];
                7        : inhib    <= |rand[3:0];
            endcase
        end
    end
endmodule


axis_sliceテスト
`timescale 1ns / 1ps
`default_nettype none

module    tb;
    parameter  stdw = 16;

    reg     c_clk;
    reg     c_rst;

    reg     enable;

    initial     c_clk <= 1'b0;
    always  #5  c_clk <= ~c_clk;

    initial begin
        c_rst       <= 1'b1;
        enable      <= 1'b0;
        #100;

        @(posedge c_clk);
        c_rst       <= 1'b0;
        #200;

        @(posedge c_clk);
        enable      <= 1'b0;
        @(posedge c_clk);
        src.ratio   <= 0;
        snk.ratio   <= 0;
        @(posedge c_clk);
        enable      <= 1'b1;
        #1000;

        @(posedge c_clk);
        enable      <= 1'b0;
        @(posedge c_clk);
        src.ratio   <= 5;
        snk.ratio   <= 3;
        @(posedge c_clk);
        enable      <= 1'b1;
        #2000;

        @(posedge c_clk);
        enable      <= 1'b0;
        @(posedge c_clk);
        src.ratio   <= 3;
        snk.ratio   <= 5;
        @(posedge c_clk);
        enable      <= 1'b1;
        #2000;

        $display("finish");
        $stop;
    end

    wire              ts1_ready;
    wire              ts1_valid;
    wire  [stdw-1:0]  ts1_data ;
    wire              ts2_ready;
    wire              ts2_valid;
    wire  [stdw-1:0]  ts2_data ;
    wire              ts3_ready;
    wire              ts3_valid;
    wire  [stdw-1:0]  ts3_data ;

    ///////////////////////////////
    axis_source
    src
    (
        .enable    (enable     ),
        .c_clk     (c_clk      ),
        .c_rst     (c_rst      ),
        .m_ready   (ts1_ready  ),
        .m_valid   (ts1_valid  ) 
    );

    reg     [stdw-1:0]    s_data;
    always @(posedge c_clk) begin
        if      (c_rst)                  s_data <= 0;
        else if (ts1_ready & ts1_valid)  s_data <= s_data + 1;
    end

    assign  ts1_data = s_data;


    ///////////////////////////////
    axis_sink
    snk
    (
        .enable    (enable     ),
        .c_clk     (c_clk      ),
        .c_rst     (c_rst      ),
        .s_ready   (ts3_ready  ),
        .s_valid   (ts3_valid  ) 
    );

    reg     [stdw-1:0]    d_data;
    always @(posedge c_clk) begin
        if      (c_rst)                  d_data <= 0;
        else if (ts3_ready & ts3_valid)  d_data <= d_data + 1;
    end

    always @(posedge c_clk) begin
        if (ts3_ready & ts3_valid) begin
            if (ts3_data != d_data) begin
                $display("error %x,%x", ts3_data, d_data);
                $stop;
            end
        end
    end


    ///////////////////////////////
    axis_slice    #(stdw)
    ts1_to_ts2 (
        c_clk, c_rst,                      // clk, rst
        ts1_ready, ts1_valid, ts1_data,    // sink
        ts2_ready, ts2_valid, ts2_data     // source
    );

    axis_slice    #(stdw)
    ts2_to_ts3 (
        c_clk, c_rst,                      // clk, rst
        ts2_ready, ts2_valid, ts2_data,    // sink
        ts3_ready, ts3_valid, ts3_data     // source
    );

endmodule

`default_nettype wire

[src] --ts1--> [ts1_to_ts2] --ts2--> [ts2_to_ts3] --ts3--> [snk]
と数珠つなぎになってます。ソース側で発生させるデータ列はカウント値、シンク側でも同じように発生させて、同じ順番になってなければエラーです。
※'X'や'Z'は見てないので、テストとしては不十分ですが…
最初はソース、シンクとも100%。途中でソースの帯域<シンクの帯域、ソースの帯域>シンクの帯域、と変化させています。

isim起動のバッチファイルとプロジェクトファイルの例。コマンドラインから「isim.bat」で実行です。
tb.prj、プロジェクト
verilog  work  ../axis_slice.v
verilog  work  ../axis_txgen.v
verilog  work  tb.v
isim.bat、実行バッチ
fuse work.tb -prj tb.prj -o tb.exe
tb.exe -gui -wdb tb.wdb

結果。まずは全体。最後まで行ってるので途中データが化けるようなことは起きて無いようです。
axis_slice_sim1.png
切り替わりのあたり。波形を見てみると、validは上流→下流に、readyは下流→上流に伝搬してるのがわかります。思った通りの動作、のはず。
axis_slice_sim0.png

ちなみにこのモジュール、「深さ1の小さなFIFO+出力レジスタ」です。後でFIFOも作りますが、「深さ1」と「深さ2以上」に大きな壁があるので分けて記述しました。
色々使えます。何度か紹介してる「周波数を出すために経路を分ける」という使い方や、非同期のループを回避するのにも使います。例えばreadyとvalidが組み合わせ回路のモジュール同士をつなぐとこうなる可能性があります。
async_loop.png
この場合、間にaxis_sliceを入れて解決します。毎回注意するのも面倒なので、非同期のモジュールはaxis_sliceでサンドイッチするようにしてます。逆に言うと気にすることなく組み合わせ回路で作れます。マルチプレクサなどは組み合わせ回路で記述してしまった方が楽だったりします。

「AXIにはデータだけじゃなくIDやLastとかあるよ?どうするの?」という話。
AXIは"ready"と"valid"と"それ以外の荷物"という関係です。なので、こう書けます。
axis_slice    #(IDの幅+データの幅+…)
sync (
    c_clk, c_rst,                                // clk, rst
    s_ready, s_valid, {s_id, s_last, s_data},    // sink
    m_ready, m_valid, {m_id, m_last, m_data}     // source
);
ここはverilog記述が楽ですね~VHDLやSystemVerilogだったら構造体使うかな?

注意点としてはレイテンシは増えることです。多くの場合周波数は上げられるので、スループットは上がります。どちら重視かはシステム次第です。

部品:AXIシミュレーション用モジュール [AXI]

作ったaxis_sliceを早速テストしたいところですが、いろんなパターンのreadyやvalidを作るのはめんどくさいです困難を極めます。

手を抜きます。

souce、マスター側
module    axis_source
(
    input  wire integer ratio,     // ratio
    input  wire         enable,    // enable
    input  wire         c_clk,     // Clock
    input  wire         c_rst,     // Reset
    input  wire         m_ready,   // Ready
    output wire         m_valid    // Valid
);
    reg     [3:0]  rand;
    reg     inhib;
    reg     valid;

    assign  m_valid = valid & ~inhib;

    always @(posedge c_clk) begin
        if (c_rst) begin
            valid    <= 1'b0;
            rand     <= 0;
            inhib    <= 1'b1;
        end
        else begin
            valid    <= enable;
            if (inhib | m_ready) begin
                rand     = $random;
                case (ratio)
                    default    : inhib    <= 0;
                    1        : inhib    <= &rand[3:0];
                    2        : inhib    <= &rand[2:0];
                    3        : inhib    <= &rand[1:0];
                    4        : inhib    <=  rand[0];
                    5        : inhib    <= |rand[1:0];
                    6        : inhib    <= |rand[2:0];
                    7        : inhib    <= |rand[3:0];
                endcase
            end
        end
    end
endmodule

sink、スレーブ側
module    axis_sink
(
    input  wire integer ratio,     // ratio
    input  wire         enable,    // enable
    input  wire         c_clk,     // Clock
    input  wire         c_rst,     // Reset
    output wire         s_ready,   // Ready
    input  wire         s_valid    // Valid
);
    reg     [3:0]  rand;
    reg     inhib;
    reg     ready;

    assign  s_ready = ready & ~inhib;

    always @(posedge c_clk) begin

        if (c_rst) begin
            ready    <= 1'b0;
            rand     <= 0;
            inhib    <= 1'b0;
        end
        else begin
            ready    <= enable;
            rand     = $random;
            case (ratio)
                default    : inhib    <= 0;
                1        : inhib    <= &rand[3:0];
                2        : inhib    <= &rand[2:0];
                3        : inhib    <= &rand[1:0];
                4        : inhib    <=  rand[0];
                5        : inhib    <= |rand[1:0];
                6        : inhib    <= |rand[2:0];
                7        : inhib    <= |rand[3:0];
            endcase
        end
    end

endmodule//

souceはvalidを、sinkはreadyを、ランダムでトグルさせます。テストデータの生成とチェックは別のテストベンチ側でやります。タイミングを生成するだけのモジュール。
有効の比率をratioで変えてて、0は100%、常に有効、1~7につれて有効の比率が下がります。4が50%ぐらい、たぶん。
こんな感じで使います。
`timescale 1ns / 1ps
`default_nettype none

module    tb;
    parameter    dw    = 16;

    reg     c_clk;
    reg     c_rst;

    reg     enable;

    integer s_ratio;
    integer d_ratio;

    initial      c_clk <= 1'b0;
    always   #5  c_clk <= ~c_clk;

    initial begin
        c_rst    <= 1'b1;
        enable   <= 1'b0;
        #100;

        @(posedge c_clk);
        c_rst    <= 1'b0;
        #200;

        /* 両方とも100% */
        @(posedge c_clk);
        enable   <= 1'b0;
        @(posedge c_clk);
        s_ratio  <= 0;
        d_ratio  <= 0;
        @(posedge c_clk);
        enable   <= 1'b1;
        #500;

        /* 送り側が多め */
        @(posedge c_clk);
        enable   <= 1'b0;
        @(posedge c_clk);
        s_ratio  <= 3;
        d_ratio  <= 5;
        @(posedge c_clk);
        enable   <= 1'b1;
        #500;

        /* 受け側が多め */
        @(posedge c_clk);
        enable   <= 1'b0;
        @(posedge c_clk);
        s_ratio  <= 5;
        d_ratio  <= 3;
        @(posedge c_clk);
        enable   <= 1'b1;
        #500;

        $display("finish");
        $stop;
    end

    wire            ts_ready;
    wire            ts_valid;
    wire  [dw-1:0]  ts_data ;

    ///////////////////////////////
    reg     [dw-1:0]    s_data;
    always @(posedge c_clk) begin
        if      (c_rst)                s_data <= 0;
        else if (ts_ready & ts_valid)  s_data <= s_data + 1;
    end

    assign  ts_data = s_data;

    ///////////////////////////////
    axis_source
    source
    (
        .ratio    (s_ratio   ),
        .enable   (enable    ),
        .c_clk    (c_clk     ),
        .c_rst    (c_rst     ),
        .m_ready  (ts_ready  ),
        .m_valid  (ts_valid  ) 
    );


    ///////////////////////////////
    axis_sink
    sink
    (
        .ratio    (d_ratio   ),
        .enable   (enable    ),
        .c_clk    (c_clk     ),
        .c_rst    (c_rst     ),
        .s_ready  (ts_ready  ),
        .s_valid  (ts_valid  ) 
    );

endmodule

`default_nettype wire

この例では直結。本来は間にテスト対象を挟んでデータのチェックを行わせます。

追記。
input wire integer ratio
この構文がisimで通らないので、変更しました。変更したソースは次の「部品:AXIストリームレジスタ、シミュレーション」に。

部品:AXIストリームレジスタ続き [AXI]

前回、
「値が有効を示す"valid"ももう一本増えます。」
って終わりましたが、いきなり訂正。増えません。

いや、正確には「必要だと思って作り始めたら実はいらなかったので消した」です。
ソースコード見直したらコメント残してましたよ。えらいぞ>過去の自分。でももうちょっとわかりやすく書こうな。
それにしてもまぁ自分の記憶の当てにならないこと。こういう文章書くと見直しになります。

どうせなので増やして設計始めた所から書いてみます。構成としてはこんな感じ。未接続のレジスタの値を制御することになります。
axis_slice.png回路3

状態数を数えます。t_valid, m_ready, m_valid, s_ready, s_validの5本なので32個です。制御対象はt_valid, m_valid, s_ready、データレジスタはt_dataとm_dataです。これらをとりあえず羅列します。あまり頭使ってません。
{t_valid, m_ready, m_valid, s_ready, s_valid} -> {tv,mr,mv,sr,sv}
{t_data, m_data, s_data} -> {td,md,sd}
tvmrmvsrsvtvmvsrtdmd
0 x 0 0 0 0 0 1 never1
0 x 0 0 1 0 0 1 never1
0 x 0 1 0 0 0 1 受信待ち
0 x 0 1 1 0 1 1 sdm_data受信
0 0 1 0 0 0 1 1 never1
0 0 1 0 1 0 1 1 never1
0 0 1 1 0 0 1 1 受信待ち
0 0 1 1 1 1 1 0sd t_data受信。これ以上は受け取れない
0 1 1 0 0 0 0 1 never1
0 1 1 0 1 0 0 1 never1
0 1 1 1 0 0 0 1 m_data送信。空になる
0 1 1 1 1 0 1 1 sdm_data送信と同時に受信
1 x 0 0 0 0 1 1 tdnever12
1 x 0 0 1 0 1 1 tdnever12
1 x 0 1 0 0 1 1 tdnever2
1 x 0 1 1 1 1 0sdtdnever2
1 0 1 0 0 1 1 0 空き待ち
1 0 1 0 1 1 1 0 空き待ち
1 0 1 1 0 illegal
1 0 1 1 1 illegal
1 1 1 0 0 0 1 1 tdm_data送信。t_data送信準備
1 1 1 0 1 0 1 1 tdm_data送信。t_data送信準備
1 1 1 1 0 illegal
1 1 1 1 1 illegal

しばらく眺めます。…この表をそのままcase文にしてもそれはそれで良いかな…無駄なロジックがあるかもしれませんが、今のシリコンからしたら微々たるものとして、もしくはコンパイラががんばるとして「完成」としても良さそうです。物を作ることが目的で最適化が必須とは限りません。さらに、全ての状態を洗い出してるので不定状態がないという安心感も。illegalの所はシミュレーションで$stopさせるとか。

ちゃんと眺めます(笑)
・出力側を見ると、常にt_valid = not s_readyです。これは「t_dataレジスタが埋まってたらもうデータは受け取れない」と読めば当たり前です。ですので、増やしたt_valid信号はいらないのでした。けど思考補助にはなってます。
・t_valid=0もしくはm_valid=0の時、つまりどちらかのレジスタが空いているときに、s_readyを0に(受信拒否)にする理由はありません。この状態も必要ありません(never1の部分)。
・t_valid=1かつm_valid=0の条件、m_dataが空いてるのにt_dataだけにデータが存在するという状態はあり得ないので、この項目は全部消えます(never2の部分)。
・t_valid=1かつm_valid=1、両方のレジスタが埋まってる状態でs_readyを1にするのは違反です(illegalの部分)。s_validが1になったらデータロストを起こします。同時にm_ready=1ならシフトレジスタ動作になってロストしませんが、そのためにはs_readyを組み合わせ回路にする必要があります。

表の不要部分を削除します。
mrmvsrsvmvsrtdmd
x 0 0 x 0 1 リセット状態
x 0 1 0 0 1 受信待ち
x 0 1 1 1 1 sdm_data受信
0 1 1 0 1 1 受信待ち
0 1 1 1 1 0sd t_data受信。これ以上は受け取れない
1 1 1 0 0 1 m_data送信。空になる
1 1 1 1 1 1 sdm_data送信と同時に受信
0 1 0 0 1 0 空き待ち
0 1 0 1 1 0 空き待ち
1 1 0 0 1 1 tdm_data送信。t_data送信準備
1 1 0 1 1 1 tdm_data送信。t_data送信準備

不要とした部分の一つが残ってますが、これをリセット状態とします。
「受信待ち」をリセット状態としても良さそうですが、m_validはともかく、s_readyが1になるのは問題です。全てのモジュールが同時にリセット解除されるという保証が無く、こちらのリセット解除の前に前段のリセットが解除されvalidが1にされた場合、データが失われます。s_readyはリセット中は0で解除後に1にします。
ほか、網掛けの「受信待ち」「空き待ち」は信号が動かないので記述する必要はありません。結果記述する条件は7個となります。
これをHDL化。
module    axis_slice
#(
    parameter  dw = 0        // Data Width
)
(
    // common
    input  wire          c_clk,      // clock
    input  wire          c_rst,      // reset
    // stream-in, sink,  slave
    output wire          s_ready,    // ready
    input  wire          s_valid,    // valid
    input  wire [dw-1:0] s_data ,    // data
    // stream-out, source, master
    input  wire          m_ready,    // ready
    output wire          m_valid,    // valid
    output reg  [dw-1:0] m_data      // data
);
    reg    [dw-1:0] t_data;
    reg    [2:1]    mvsr;
    assign {m_valid,s_ready} = mvsr;

    always @(posedge c_clk) begin
        casex ({c_rst,m_ready,m_valid,s_ready,s_valid})
            5'b1xxxx : begin  mvsr <= 2'b00;                     end
            5'b0x00x : begin  mvsr <= 2'b01;                     end
            5'b0x011 : begin  mvsr <= 2'b11;  m_data <= s_data;  end
            5'b00111 : begin  mvsr <= 2'b10;  t_data <= s_data;  end
            5'b01110 : begin  mvsr <= 2'b01;                     end
            5'b01111 : begin  mvsr <= 2'b11;  m_data <= s_data;  end
            5'b0110x : begin  mvsr <= 2'b11;  m_data <= t_data;  end
        endcase
    end
endmodule
表をそのままcaseにしただけ。
ただし、この記述にするときはちゃんとコメントや文章残しましょう。でないと後から見ると「ナニコレ?」状態になります。if~then~elseで書き直せばソースでもある程度意味がわかる記述になりますが、やっぱりコメントは残しましょう。

詠み人知らずの格言:昨日の自分は別の人。


追記
・c_rstもcase文の条件に入れてしまってます。普通の書き方(if (c_rst) ~ else case ~)にしてもリソース、速度ともに変わらなかったので(ISE S6でテスト)そのままにしてます。条件によっては変わるかも。
・「m_data <= s_data;」の記述を動作に関係ない所(例えば5'b01110のライン)に書くと、データラッチ条件のデコードビットが減って回路が小さく速くなる可能性があります。S6では変わりませんでした。
合成結果見たところ、がっつり最適化してくれてるようです。ありがたや~

追記その2
この回路、意外と入力のファンアウトが多いです。それが原因の問題には今のところ当たったことは無いですが、もし当たったら厄介そうです。
入力もレジスタ化するのは結構難儀なので、当たったときに考えようかと…(笑)

部品:AXIストリームレジスタ [AXI]

AXIストリームの単純なリピーターを作ってみます。
プロトコルでは無く、タイミングを考えるレイヤーです。

受け取ったデータをラッチしてそのまま出力するだけ。(その1)で経路を分割するときにレジスタを入れる、という話がありましたが、経路が長くなったときに周波数を出すために入れるレジスタにもなります。
単純なようですが、意外と奥が深いです。そしてこの部品がAXI設計時の要となります。これを作っておかないと色々行き詰まる事が後からわかりました。
経路を分ける、切るという意味合いで、DecoupleとかSliceとか呼んでます。
宣言はこんな感じ。outputのreg/wireは場合によって変わります。ホントはsouce、sinkという名前にしたいところですが、同じ「s」なので、slave、masterとなってます。
module  axis_slice
#(
  parameter  dw = 0    // Data Width
)
(
  // common
  input  wire          c_clk,    // clock
  input  wire          c_rst,    // reset
  // stream-in, sink, write, slave
  output reg           s_ready,  // ready
  input  wire          s_valid,  // valid
  input  wire [dw-1:0] s_data ,  // data
  // stream-out, source, read, master
  input  wire          m_ready,  // ready
  output reg           m_valid,  // valid
  output reg  [dw-1:0] m_data    // data
);
  /* 本体 */
endmodule

AXIのハンドシェイクのタイミングです。
axis_handshake.pngタイミング
"ready"と"valid"の組み合わせなので、4パターンあります。
validready状態
00アイドル
01アイドル(転送催促?)
10ウェイト
11転送成立
[valid,ready]="00"と"01"は一緒にして良いかも。

この波形からまず思いつくのはこんな回路。
slice01.png回路1
assign	s_ready	= m_ready;

always @(posedge c_clk) begin
	if (c_rst) begin
		m_valid	<= 1'b0;
	end
	else if (s_ready) begin
		m_valid	<= s_valid;
		m_data	<= s_data;
	end
end

"ready"がクロックイネーブルとして使われた、普通のパイプラインレジスタですね。これはこれで使います。DFFを複数段にしてn段のディレイとしても使います。
追記:この回路はAXIとしては使ってはいけません。デッドロックします。

しかし、経路分割としては不十分。"ready"が分割されてません。"ready"の経路が長いままでクリティカルパスになる可能性があります。また、"ready"がレジスタ出力かどうかは後段の"ready"出力によります。この回路では不明です。
あと、せっかくレジスタなのに、受け側が"ready=0"だと、レジスタが空いていても受け取れません。レジスタが空いてたら受け取ってく欲しいですよね。「レジスタが空いてる」=「"valid"が"0"」ですので、こうしてみます。
slice02.png回路2
assign	s_ready	= m_ready | ~m_valid;
/*他同じ*/

機能的には良さそうですが、この回路を入出力端で使ってはいけません。"ready"が組み合わせ出力です。色々弊害が起きます。他の回路でもこのパターンの回路を使うと、"ready"がクリティカルパスになります。"ready"が数珠つなぎになりますからね。

一工夫必要です。

感覚的には、使っちゃダメと言った回路2の方がAXIっぽいと思います。回路1では"valid"が"data"と同じ扱いですが、回路2では「レジスタ内のデータが有効だよ~」というフラグのような扱いになってます。考え方はこちらから発展してます。

"ready"をレジスタ出力にすると後段の"ready"入力から1クロック遅れます。後段が「待った」と言ってもそれが前段に伝わるのは1クロック後です。その間に前段の転送は成立してしまうので、どこかに保存しておかないといけません。ということで、「どこか」=もう一段データを保存するレジスタが必要になります。値が有効を示す"valid"ももう一本増えます。

続く

OpenIndiana 設定メモ [PC]

ntpクライアントの設定。

NTPサーバーMFEED
# vi /etc/inet/ntp.conf
server  ntp.jst.mfeed.ad.jp とか

# svcadm enable ntp
# svcs ntp
STATE          STIME    FMRI
online         18:55:14 svc:/network/ntp:default


ユーザをsuさせたい。
usermod -R root daresore


ドライブ情報を見る。
# iostat -En


vncを有効にする。151a8デスクトップ版ではインストール済みなので設定だけ。
# vi /etc/gdm/custom.conf

[security]
DisallowTCP=false

[xdmcp]
Enable=true
保存。

# svcadm enable xvnc-inetd
# svcadm restart gdm

# svcs
オンラインになってることを確認。

これで一応つながります。
しかしこのままだと、vncクライアントを終了させるとログインセッション以下、全部終了されてしまうので、少し不便です。
# svccfg -s xvnc-inetd
svc:/application/x11/xvnc-inetd> editprop
viが立ち上がるので、以下を編集、保存。
setprop inetd/wait = boolean: true

svc:/application/x11/xvnc-inetd> exit
# svcadm restart xvnc-inetd

これでvncクライアントを閉じてもログインセッションは生き続けます。ただし、立ち上げっぱなしだとパスワード無しでいきなりつながるので、セキュリティ上は大問題でしょう。なにか設定はあると思いますが、今のところこのまま。

好き嫌いと効率 [HDL]

いくつかHDLのサンプルを上げてますが、verilog HDLばかりです。

でも実は言語としてはVHDLの方が好みです。記述量は増えますが、型管理が厳密で妙な値の変換による齟齬に悩まされないところとか、同期非同期リセットの記述がはっきり分かれてるとか、自分の型定義が便利とか、が良いです。あとVHDLは文法が通れば曖昧な解釈は無いだろうという点も好きです。
ついでにツールもずっとAlteraのQuartus II、というよりSOPC Builderべったりです。Nios IIを使わない事は良くありますが、SOPC Builderを使わない事はほとんどありませんでした。

けど、最近はXilinx ISE+verilogばかりだったりします。verilogの妙な癖のカンがついてきたのと、たまたま最近使ったボードがXilinxだったぐらいが理由でしょうか。また、AXIで作るようになって、SOPC Builderじゃ無くてもつなぐのが楽になったというのもある感じです。QsysがAXIをサポートしたら…やっぱり楽な方に転ぶと思いますが(笑)

結局何でも良かったりします。VHDLとverilog、どっちが優れた言語か、なんて話は興味ありません。言語の細かい文法をろくに覚えてなかったりして、毎回書籍や前のソースを参照してます。その代わり、全く知らない言語でも取っつくようにしてます。「道具」ですから、目的に合っていれば使うし、合わなければ別の道具を使います。FPGAだからHDLで書かなければならないワケでもありませんし、ロジックを使わなければならない理由もありません。CPU(DSP)+C/C++の方が良いならそうします。PC+GPGPUの方が適したアプリケーションもあります。

別に言語マスターになりたいわけでは無いので、これで良いとも思ってます。
一番良いのは、何も書かずに物ができあがることです。

「手を抜くための努力は惜しまない」

HP ProLiant G7 ML110 ESXi導入 [PC]

さて、とりあえずOI151a入れて低消費電力サーバーとしてひとまず安定してるこのサーバーですが、これだけ素性が良いとやっぱり欲が出てきます。FPGAのコンパイル任せたりとか、あれやこれや・・・そうなるとWindows系とLinux系の環境が欲しくなります。仮想環境?
でもzfsをストレージとして使いたいのでSolaris系は残したい。VirtualBoxも考えましたが、やはりここはハイパーバイザー、VMware ESXiでしょう!。何しろハイパーだし(笑)Solaris系の仮想環境はイマイチよくわかりません。

ということで早速USBを別の2GBのに差し替え、VMwareのからESXi 5.0をダウンロード、同時にライセンスも取得、CDRに焼いて起動。BIOSのパワー制御の設定は「OS Control」にしておかないとピンク画面になるそうです。
インストールに関してはたくさん紹介されてるので割愛。G7でも普通通り導入できました。SSH開放してvSphere Clientインストールしてハイパーバイザー環境があっさりできあがり。上手く行ったらメモリを16GBにしようかな~とか考えてます。

ESXiは仮想マシンのファイルを置いておくデータストレージが必要です。外部のiSCSIやNFSサーバーを使うのが想定された使い方ですが、別途サーバーを置くのは避けたいので、内部のSATAに小容量のSSDを接続。データストレージとします。

仮想環境でも普段通りOI151aのインストールは完了します。物理的なCDRではなくISOファイルが使えるのでさらに楽です。
raidz2ボリュームのimport。ここで分かれ目です。zfsのHDDはESXi側で認識されているので、仮想マシンへそのまま渡すにはRDM(Raw Device Mapping)にしなくてはなりません。RDMのやり方は"ESXi RDM"などで検索するとたくさん出てきます。SSHコンソールから、
# vmkfstools -z /vmfs/devices/disks/"妙に長いHDDの名前" 
  ./"RDMファイルの名前".vmdk -a lsilogic
と台数分RDMのファイルを作成し、仮想マシンに追加すればOKとなります。raidz2の4台のHDDも問題なく登録され、仮想oiから"zpool import"でマウントできます。データ転送速度もネイティブ並み、scrubも通ってます。
ただ、自分の環境ではスピンダウンの設定が上手く働きません。何か設定おかしいのかな?HDDの健康のため回しっぱなしならRDMでも良いのですが…

もう一つの方法、「PCI PassThrough」があります。HDDのコントローラ丸ごと仮想環境に渡してしまうという秘技です。これなら!……標準のCeleron G530はこれが出来ません。Vt-dが無効になってるんです。

PCIパススルーをやってみたい。この辺から目的と手段を入れ違えてます(先のRDMで一応の目的は達成されてるのですから)。ということで「Xeon E3 1220L」を購入。HPがラインアップしてるのは1220(L無し。4コア4スレッド)で、こちらの方が確実に動作するのですが、2コア4スレッド、TPD20Wに惹かれ、ちょっと冒険です。

CPU換装にはT15のトルクスドライバー(星形のやつ)が必要ですが、どのご家庭にも必ず1本はあるので問題ないでしょう。グリスを塗り直してヒートシンクを戻し、電源投入。…3分ぐらい画面真っ黒でした。やってしまったかと思った頃、画面が出て「1220L」の文字が!ちゃんと認識されてるようです。
※本来のターボ動作をしてるかは未確認です。
消費電力はあまり変わらないみたいです。同じ2コアのSandy Bridgeでキャッシュが1.5倍、HTが有効という差です。アイドルで気持ち1~2W高い感じでしょうか。

さっそくvShpere Clientからの確認。
esxi_summ.pngサマリ
ばっちり。
パススルーの設定画面。
esxi_pt.pngパススルー
完璧っ!……え?6ポート?
ヤな予感を感じつつ、リブートしたところ…やはり、ストレージとして使ってたSATA接続のSSDもまとめてパススルーされ、ESXiから見えなくなってましたよorz
当たり前といえば当たり前。が、気づきませんでした。

どこかからESXiのデータストレージを確保しなくてはなりませんが、ESXiはUSBのストレージを許してません※。PCIeに拡張しようにもSilcon Imageなどの安いカードは軒並み全滅。Adaptecなど有名どころなら使えますが、価格と消費電力、そしてG7のファンの騒音が増える(別のカードで確認済み)ので躊躇してます。G7単体では手詰まりです。

外部に別途NFSサーバーを立てて、そこにストレージを作り、OI151aをインストール、パススルーさせたHDDのコントローラのzfsのアクセス。これは上手くいってます。が、サーバーを別に用意するのは…これはさっきも書きましたね。

RDMかRAIDカードかNFSサーバーか、の3択となりました。
今はOI151aに戻してます。VirtualBoxを入れてみようかと。

ちょっと前ならI/OデータのUSL-5Pとかで試したいところですが、さすがに入手が…NFSが出来るのかも情報少ないですし。OpenBlockSなどなら安全そうですが、ちょっと高いな…
ということで密かに「Raspberry Pi」に期待してます。NFSサーバーが動くかは知らないのですが、SDカードをNFS exportできれば1W以下のデータストレージとして使えないかな、と。

※追記
色々試してはいますが自分のスキルでは無理そう
・usbarbitratorを止める。
→これを止めると仮想マシンに渡されてたUSBメモリがESXiに戻ってくる。
・/dev/disksにUSBデバイス出てくる。
・fdiskでパーティション作成、タイプをvmfsにする。
・vmkfstoolでvmfs作成。
→失敗。カーネルがサポートしてないよ~的なエラーが出る。
modprobeとかで見るとvmfsはあるが、usbをファイルシステムとして扱うモジュールが無さそう?
で、あきらめ状態。


特殊ネジ用ドライバー DT-15 エンジニア

特殊ネジ用ドライバー DT-15 エンジニア

  • 出版社/メーカー: エンジニア
  • メディア: エレクトロニクス



AXIの勉強(その1) [AXI]

そのいくつまで行くかは不明ですが。

参考にしているのはARM本家の仕様書Xilinxの資料など。まだベータですがAlteraのQsysも追いかけてます。
タイミングチャートの作成にはTimingChartViewerをお借りしてます。同期回路限定ですが便利に使わせていただいてます。ありがとうございます。

用語とか勝手に呼び替えてしまってるところがあります。適当に読み替えて下さい。

AXIのタイミングは、良く資料などでも出てきますが、
axi_readburst.pngリード
axi_writeburst.pngライト
という感じです。
なんか複雑そうですが、実はタイミングとして見ないとならないのは"ready"と"valid"だけです。もう一つのAXI規格の「AXI stream」もそうですが、"ready"と"valid"が両方とも"1"(有効)の時にデータ(荷物、ペイロード)が転送される、という仕組みになってます。この仕組みはAXI3もAXI4も同じです。
図中の"last"信号や、"id"、"size"、"burst"、"lock"などいろいろな信号がありますが、これら全て荷物、ペイロードとして扱います。"ready"と"valid"と"荷物"という関係です。
これに関してはARMの資料にも記述されてます。以下抜粋ですが、これもよく見かける図ですね。
axt_read_channel.pngリード
axi_write_channel.pngライト
この図だと、リードが2チャンネルで、ライトが3チャンネルとアンバランスな感じがしますが、リードのデータチャンネルにライトのレスポンスと同等の情報が載ってるので(OKAYなどを返してる)、行き交う情報の量はだいたい対称です。
届いた荷物の中身が重要であって、荷物がいつ届いたかに関してはあまり考えなくて良くなります。マスター側は荷物の準備が出来たら"valid"を有効にする、スレーブ側は荷物の受け入れ準備が出来たら"ready"を有効にする、両方が有効なら転送成立、という考え方です。
ちょっと図を変えるとその分野の人には見慣れた図になったりします。
axi_read_txfr.pngリード
axi_write_txfr.pngライト
ra、waはリードライトのアドレス、rd、wdはデータ、+lastはフラグを付加といった感じです。RS-232Cやネットワークとかの通信でもよく見る、データ通信プロトコルの図になりました。
AXIって物理的な通信経路が複数本あるだけで考え方はネットワークに近いと見た方が良いと私は思ってます。ユーザーが作るマスター・スレーブの回路は、このプロトコルを処理するシーケンサーという事になります。

これによる最大の利点、設計時にタイミングのことを考えなくて良い(タイミングとプロトコルを分けて考えられる)という点だと思います。例えばマスターとスレーブが離れた位置にあって、信号到達までに時間がかかり速度が出ない、という場合、通信経路にレジスタを入れて経路を分割してもプロトコル上は影響ありません。
axi_read_txfr2.pngリード、経路分割
途中にレジスタが入って経路が分割されても通信は成り立ちます。見た目には赤点線のように、到着時間が変わった=矢印の傾きが変わった、のと等価です。
レジスタが入ってるので、個々のチャンネルのタイミングは大きく変わってるはずです。が、AXIは届いた荷物の中身が重要で、届きさえすれば良いという仕組みですから、タイミングの違いは無視してかまわない事になります。これが設計をすごく楽にします。

個々のチャンネルはAXIのストリームと同じですから、次からはその辺の部品を作っていきたいと思います。

念のため

ここに置いてあるコンテンツ(HDLなど)は非商用目的に限りご利用いただけます。

実務で使う方がいるとは思いませんが、念のため。
前の10件 | -
-|2012年04月 |2012年05月 ブログトップ

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。