Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

アトリビュート

アトリビュートは変数宣言などいくつかの宣言に注釈を付けることができます。

sv アトリビュート

sv アトリビュートは SystemVerilog のアトリビュートを表し、(* *) という形式の SystemVerilog アトリビュートに変換されます。

module ModuleA {
    #[sv("ram_style=\"block\"")]
    let _a: logic<10> = 1;
    #[sv("mark_debug=\"true\"")]
    let _b: logic<10> = 1;
}

allow アトリビュート

allow アトリビュートは指定されたリントチェックを無効化するために使用できます。

module ModuleA {
    #[allow(unused_variable)]
    let a: logic<10> = 1;
}

指定可能なリント名は以下の通りです。

  • unused_variable
  • unassign_variable
  • missing_reset_statement
  • missing_port
  • initial_assign
  • multiple_assign

ポータブルでない構文

initial_assignmultiple_assign は他のリント名とは性質が異なり、ポータブルでない構文、すなわち動作するかどうかがターゲットデバイスやツールチェーンに依存する構文を明示的に許可するためのものです。これらは対象となる変数の宣言に記述します。

initial_assigninitial ブロックでその変数へ代入することを許可します。これはターゲットデバイスがコンフィギュレーション時に変数を初期化することに依存しており、ASIC の合成ツールはこれを無視します。$readmemh$readmemb のような関数呼び出しの出力引数を介した代入にも同様にこのアトリビュートが必要です。initial ブロックの内部で宣言された変数は設計の状態ではなく手続き的なローカル変数であるため、アトリビュートは不要です。

module ModuleA (
    i_clk: input clock,
) {
    #[allow(initial_assign)]
    var count: logic<16>;

    #[allow(initial_assign)]
    var rom: logic<32> [1024];

    initial {
        count = '0;
        $readmemh("rom.hex", rom);
    }

    always_ff {
        count = count + 1;
    }

    #[allow(unused_variable)]
    let _a: logic<32> = rom[0];
}

initial ブロックは駆動プロセスではないため、initial_assign の付いた変数は上の count のようにプロセスから駆動することもできます。そのために multiple_assign は必要ありません。

multiple_assign は複数のプロセスからその変数へ代入することを許可します。これは FPGA における真のデュアルポート SRAM の推論に必要です。

module ModuleB (
    i_clk0 : input  'a clock    ,
    i_clk1 : input  'b clock    ,
    i_en0  : input  'a logic    ,
    i_en1  : input  'b logic    ,
    i_addr0: input  'a logic<5> ,
    i_addr1: input  'b logic<5> ,
    i_data0: input  'a logic<32>,
    i_data1: input  'b logic<32>,
    o_data : output 'a logic<32>,
) {
    #[allow(multiple_assign)]
    var ram: 'a logic<32> [32];

    always_ff (i_clk0) {
        if i_en0 {
            ram[i_addr0] = i_data0;
        }
    }

    unsafe (cdc) {
        always_ff (i_clk1) {
            if i_en1 {
                ram[i_addr1] = i_data1;
            }
        }
    }

    assign o_data = ram[i_addr0];
}

SystemVerilog では always_ff で書き込まれる変数を他のプロセスから書き込むことは禁止されています。そのため、いずれかのアトリビュートが付いた変数に書き込む always_ff は通常の always として出力されます。always_comb にも同じ制限がありますが、こちらは変換されないため、複数の always_comb/assign 宣言から一つの変数を駆動するコードは Veryl では受理されても SystemVerilog のツールでは拒否されます。

これらの構文をサポートしないターゲットのプロジェクトに紛れ込まないよう、依存プロジェクトのコードでこれらを受け入れるかどうかは利用側が [lint.portability] で決定します。自身のコードではアトリビュートは常に尊重されます。

ifdef/ifndef/elsif/else アトリビュート

ifdefifndef アトリビュートは定義された値によってコードブロックを有効にするかどうかを制御するために使用することができます。さらに、ifdefifndef のついたコードブロックに続けてオプションとして elsifelse アトリビュートの付いたブロックを書くこともできます。

以下の例はこれらのアトリビュートの使用方法と、各コードブロックが定義された値によって有効になる様子を示しています。

  • ifdef/elsif/else の順に宣言されたアトリビュート
    • もし DEFINE_A が定義されていれば、#[ifdef(DEFINE_A)] のついたコードブロック(コードブロックa)が有効になり、#[ifndef(DEFINE_B)]#[else] のついたコードブロック(コードブロックbとc)は無効になります。
    • DEFINE_A が定義されておらず、 DEFINE_B が定義されていれば、#[elfif(DEFINE_B)] のついたコードブロック(コードブロックb)が有効になり、#[ifndef(DEFINE_A)]#[else] のついたコードブロック(コードブロックaとc)は無効になります。
    • DEFINE_ADEFINE_B が定義されていなければ、#[else] のついたコードブロックが有効になり、#[ifndef(DEFINE_A)]#[elsif(DEFINE_B)] のついたコードブロック(コードブロックaとb)は無効になります。
  • ifndef/else の順に宣言されたアトリビュート
    • もし DEFINE_D が定義されていなければ、#[ifndef(DEFINE_D)] のついたコードブロック(コードブロックd)が有効になり、#[else] のついたコードブロック(コードブロックe)は無効になります。
    • DEFINE_D が定義されていれば、#[else] のついたコードブロック(コードブロックe)が有効になり、#[ifndef(DEFINE_D)] のついたコードブロック(コードブロックd)は無効になります。
module ModuleA {
    #[ifdef(DEFINE_A)]
    {
        // コードブロック a
        let _a: logic<10> = 1;
    }
    #[elsif(DEFINE_B)]
    {
        // コードブロック b
        let _a: logic<10> = 2;
    }
    #[else]
    {
        // コードブロック c
        let _a: logic<10> = 3;
    }

    #[ifndef(DEFINE_D)]
    {
        // コードブロック d
        let _b: logic<10> = 4;
    }
    #[else]
    {
        // コードブロック e
        let _b: logic<10> = 5;
    }
}

生成されたコードにおける末尾カンマ周りの複雑な調整を回避するため、カンマ区切りリストの最後のアイテムにifdefをつけることは禁止されています。

expand アトリビュート

expand アトリビュートが設定されているとき、modport のような構造化されたポートはVerilog のポートに展開されます。合成ツールによってはトップモジュールがそのようなポートを含んではならない場合があり、そのような場合にこのアトリビュートを使うことができます。使用可能な引数は以下の通りです。

  • modport: ポート方向が modport のポートを展開する
interface InterfaceA::<W: u32> {
    var ready: logic   ;
    var valid: logic   ;
    var data : logic<W>;

    modport master {
        ready: input ,
        valid: output,
        data : output,
    }

    modport slave {
        ready: output,
        valid: input ,
        data : input ,
    }
}

#[expand(modport)]
module ModuleA (
    slave_if : modport InterfaceA::<8>::slave  [4],
    master_if: modport InterfaceA::<8>::master [4],
) {
    for i in 0..4 :g {
        connect slave_if[i] <> master_if[i];
    }
}

module ModuleB {
    inst a_if: InterfaceA::<8> [4];
    inst b_if: InterfaceA::<8> [4];

    inst u: ModuleA (
        slave_if : a_if,
        master_if: b_if,
    );
}

align アトリビュート

align アトリビュートはフォーマッタの垂直方向の整列を制御することができます。numberalign の引数として指定されたとき、全ての数値は整列されます。identifier も使用可能です。

module ModuleA {
    let a  : logic<32> = 1;
    let aa : logic<32> = 1;
    let aaa: logic<32> = 1;

    let _b: logic = {
        a[0] repeat 1, a[0] repeat 1, aa[1] repeat 8, aa[1] repeat 8, aaa[2] repeat 16, aaa[2] repeat 16, a[0] repeat 1,
        aa[1] repeat 8, aaa[2] repeat 16, a[0] repeat 1,
    };

    #[align(number, identifier)]
    let _c : logic = {
        a  [0 ] repeat 1 , a  [0 ] repeat 1 , aa [1 ] repeat 8 , aa [1 ] repeat 8 , aaa[2 ] repeat 16,
        aaa[2 ] repeat 16, a  [0 ] repeat 1 , aa [1 ] repeat 8 , aaa[2 ] repeat 16, a  [0 ] repeat 1 ,
    };
}

fmt アトリビュート

fmt アトリビュートはフォーマットの方法を制御することができます。以下の引数がサポートされています。

  • compact: 改行なしのコンパクトなフォーマット
module ModuleA {
    #[fmt(compact)]
    {
        inst u1: $sv::Module #( A: 1, B: 2 ) ( x: 1, y: _ );
        inst u2: $sv::Module #( A: 1, B: 2 ) ( x: 1, y: _ );
        inst u3: $sv::Module #( A: 1, B: 2 ) ( x: 1, y: _ );
        inst u4: $sv::Module #( A: 1, B: 2 ) ( x: 1, y: _ );
    }
}
  • skip: veryl fmt はモジュール、インターフェース、パッケージをフォーマットしない