アトリビュート

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

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
  • missing_reset_statement
  • missing_port

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,
    };

    #[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,
    };
}

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: _ );
    }
}